Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/226.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android图像视图缩放_Android_Android Layout_Android Intent_Android Widget - Fatal编程技术网

Android图像视图缩放

Android图像视图缩放,android,android-layout,android-intent,android-widget,Android,Android Layout,Android Intent,Android Widget,我使用的是来自示例的代码 用于缩放图像视图。在ScaleListener上,我添加了scalegestruedetector.getFocusX()和getFocusY(),用于缩放手势焦点的内容。它工作得很好 问题是,在第一次多点触摸时,整个图像绘制位置正在更改为当前接触点并从那里进行缩放。您能帮我解决这个问题吗? 这是我的TouchImageView代码示例 public class TouchImageViewSample extends ImageView { private Pain

我使用的是来自示例的代码 用于缩放图像视图。在ScaleListener上,我添加了
scalegestruedetector.getFocusX()和getFocusY()
,用于缩放手势焦点的内容。它工作得很好

问题是,在第一次多点触摸时,整个图像绘制位置正在更改为当前接触点并从那里进行缩放。您能帮我解决这个问题吗?

这是我的TouchImageView代码示例

public class TouchImageViewSample extends ImageView {

private Paint borderPaint = null;
private Paint backgroundPaint = null;

private float mPosX = 0f;
private float mPosY = 0f;

private float mLastTouchX;
private float mLastTouchY;
private static final int INVALID_POINTER_ID = -1;
private static final String LOG_TAG = "TouchImageView";

// The ‘active pointer’ is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;

public TouchImageViewSample(Context context) {
    this(context, null, 0);
}

public TouchImageViewSample(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;

// Existing code ...
public TouchImageViewSample(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    // Create our ScaleGestureDetector
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());

    borderPaint = new Paint();
    borderPaint.setARGB(255, 255, 128, 0);
    borderPaint.setStyle(Paint.Style.STROKE);
    borderPaint.setStrokeWidth(4);

    backgroundPaint = new Paint();
    backgroundPaint.setARGB(32, 255, 255, 255);
    backgroundPaint.setStyle(Paint.Style.FILL);

}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    // Let the ScaleGestureDetector inspect all events.
    mScaleDetector.onTouchEvent(ev);

    final int action = ev.getAction();
    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN: {
        final float x = ev.getX();
        final float y = ev.getY();

        mLastTouchX = x;
        mLastTouchY = y;

        mActivePointerId = ev.getPointerId(0);
        break;
    }

    case MotionEvent.ACTION_MOVE: {
        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
        final float x = ev.getX(pointerIndex);
        final float y = ev.getY(pointerIndex);

        // Only move if the ScaleGestureDetector isn't processing a gesture.
        if (!mScaleDetector.isInProgress()) {
            final float dx = x - mLastTouchX;
            final float dy = y - mLastTouchY;

            mPosX += dx;
            mPosY += dy;

            invalidate();
        }

        mLastTouchX = x;
        mLastTouchY = y;
        break;
    }

    case MotionEvent.ACTION_UP: {
        mActivePointerId = INVALID_POINTER_ID;
        break;
    }

    case MotionEvent.ACTION_CANCEL: {
        mActivePointerId = INVALID_POINTER_ID;
        break;
    }

    case MotionEvent.ACTION_POINTER_UP: {
        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        final int pointerId = ev.getPointerId(pointerIndex);
        if (pointerId == mActivePointerId) {
            // This was our active pointer going up. Choose a new
            // active pointer and adjust accordingly.
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mLastTouchX = ev.getX(newPointerIndex);
            mLastTouchY = ev.getY(newPointerIndex);
            mActivePointerId = ev.getPointerId(newPointerIndex);
        }
        break;
    }
    }

    return true;
}

/*
 * (non-Javadoc)
 * 
 * @see android.view.View#draw(android.graphics.Canvas)
 */
@Override
public void draw(Canvas canvas) {
    super.draw(canvas);
    canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, borderPaint);
}

@Override
public void onDraw(Canvas canvas) {
    canvas.drawRect(0, 0, getWidth() - 1, getHeight() - 1, backgroundPaint);
    if (this.getDrawable() != null) {
        canvas.save();
        canvas.translate(mPosX, mPosY);

        Matrix matrix = new Matrix();
        matrix.postScale(mScaleFactor, mScaleFactor, pivotPointX,
                pivotPointY);
        // canvas.setMatrix(matrix);

        canvas.drawBitmap(
                ((BitmapDrawable) this.getDrawable()).getBitmap(), matrix,
                null);

        // this.getDrawable().draw(canvas);
        canvas.restore();
    }
}

/*
 * (non-Javadoc)
 * 
 * @see
 * android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable
 * )
 */
@Override
public void setImageDrawable(Drawable drawable) {
    // Constrain to given size but keep aspect ratio
    int width = drawable.getIntrinsicWidth();
    int height = drawable.getIntrinsicHeight();
    mLastTouchX = mPosX = 0;
    mLastTouchY = mPosY = 0;

    int borderWidth = (int) borderPaint.getStrokeWidth();
    mScaleFactor = Math.min(((float) getLayoutParams().width - borderWidth)
            / width, ((float) getLayoutParams().height - borderWidth)
            / height);
    pivotPointX = (((float) getLayoutParams().width - borderWidth) - (int) (width * mScaleFactor)) / 2;
    pivotPointY = (((float) getLayoutParams().height - borderWidth) - (int) (height * mScaleFactor)) / 2;
    super.setImageDrawable(drawable);
}

float pivotPointX = 0f;
float pivotPointY = 0f;

private class ScaleListener extends
        ScaleGestureDetector.SimpleOnScaleGestureListener {

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        mScaleFactor *= detector.getScaleFactor();

        pivotPointX = detector.getFocusX();
        pivotPointY = detector.getFocusY();

        Log.d(LOG_TAG, "mScaleFactor " + mScaleFactor);
        Log.d(LOG_TAG, "pivotPointY " + pivotPointY + ", pivotPointX= "
                + pivotPointX);
        mScaleFactor = Math.max(0.05f, mScaleFactor);

        invalidate();
        return true;
    }
}
这里是我如何在我的活动中使用它

ImageView imageView = (ImageView) findViewById(R.id.imgView);

int hMargin = (int) (displayMetrics.widthPixels * .10);
int vMargin = (int) (displayMetrics.heightPixels * .10);

RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(displayMetrics.widthPixels - (hMargin * 2), (int)(displayMetrics.heightPixels - btnCamera.getHeight()) - (vMargin * 2));
params.leftMargin = hMargin;
params.topMargin =  vMargin;
imageView.setLayoutParams(params);
imageView.setImageDrawable(drawable);
使用的变量为:

// These matrices will be used to move and zoom image
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();

// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;

// Remember some things for zooming
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
String savedItemClicked;

我创建了自己的自定义图像视图,并使用“按比例缩放”。s代码没有限制/边框,因此用户可以将图像拖离屏幕。这会解决它的

以下是CustomImageView类:

    public class CustomImageVIew extends ImageView implements OnTouchListener {


    private Matrix matrix = new Matrix();
    private Matrix savedMatrix = new Matrix();

    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;

    private int mode = NONE;

    private PointF mStartPoint = new PointF();
    private PointF mMiddlePoint = new PointF();
    private Point mBitmapMiddlePoint = new Point();

    private float oldDist = 1f;
    private float matrixValues[] = {0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f};
    private float scale;
    private float oldEventX = 0;
    private float oldEventY = 0;
    private float oldStartPointX = 0;
    private float oldStartPointY = 0;
    private int mViewWidth = -1;
    private int mViewHeight = -1;
    private int mBitmapWidth = -1;
    private int mBitmapHeight = -1;
    private boolean mDraggable = false;


    public CustomImageVIew(Context context) {
        this(context, null, 0);
    }

    public CustomImageVIew(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomImageVIew(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setOnTouchListener(this);
    }

    @Override
    public void onSizeChanged (int w, int h, int oldw, int oldh){
        super.onSizeChanged(w, h, oldw, oldh);
        mViewWidth = w;
        mViewHeight = h;
    }

    public void setBitmap(Bitmap bitmap){
        if(bitmap != null){
            setImageBitmap(bitmap);

            mBitmapWidth = bitmap.getWidth();
            mBitmapHeight = bitmap.getHeight();
            mBitmapMiddlePoint.x = (mViewWidth / 2) - (mBitmapWidth /  2);
            mBitmapMiddlePoint.y = (mViewHeight / 2) - (mBitmapHeight / 2);

            matrix.postTranslate(mBitmapMiddlePoint.x, mBitmapMiddlePoint.y);
            this.setImageMatrix(matrix);
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event){
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            savedMatrix.set(matrix);
            mStartPoint.set(event.getX(), event.getY());
            mode = DRAG;
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            oldDist = spacing(event);
            if(oldDist > 10f){
                savedMatrix.set(matrix);
                midPoint(mMiddlePoint, event);
                mode = ZOOM;
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_UP:
            mode = NONE;
            break;
        case MotionEvent.ACTION_MOVE:
            if(mode == DRAG){
                drag(event);
            } else if(mode == ZOOM){
                zoom(event);
            } 
            break;
        }

        return true;
    }



   public void drag(MotionEvent event){
       matrix.getValues(matrixValues);

       float left = matrixValues[2];
       float top = matrixValues[5];
       float bottom = (top + (matrixValues[0] * mBitmapHeight)) - mViewHeight;
       float right = (left + (matrixValues[0] * mBitmapWidth)) -mViewWidth;

       float eventX = event.getX();
       float eventY = event.getY();
       float spacingX = eventX - mStartPoint.x;
       float spacingY = eventY - mStartPoint.y;
       float newPositionLeft = (left  < 0 ? spacingX : spacingX * -1) + left;
       float newPositionRight = (spacingX) + right;
       float newPositionTop = (top  < 0 ? spacingY : spacingY * -1) + top;
       float newPositionBottom = (spacingY) + bottom;
       boolean x = true;
       boolean y = true;

       if(newPositionRight < 0.0f || newPositionLeft > 0.0f){
           if(newPositionRight < 0.0f && newPositionLeft > 0.0f){
               x = false;
           } else{
               eventX = oldEventX;
               mStartPoint.x = oldStartPointX;
           }
       }
       if(newPositionBottom < 0.0f || newPositionTop > 0.0f){
           if(newPositionBottom < 0.0f && newPositionTop > 0.0f){
               y = false;
           } else{
               eventY = oldEventY;
               mStartPoint.y = oldStartPointY;
           }
       }

       if(mDraggable){
           matrix.set(savedMatrix);
           matrix.postTranslate(x? eventX - mStartPoint.x : 0, y? eventY - mStartPoint.y : 0);
           this.setImageMatrix(matrix);
           if(x)oldEventX = eventX;
           if(y)oldEventY = eventY;
           if(x)oldStartPointX = mStartPoint.x;
           if(y)oldStartPointY = mStartPoint.y;
       }

   }

   public void zoom(MotionEvent event){
       matrix.getValues(matrixValues);

       float newDist = spacing(event);
       float bitmapWidth = matrixValues[0] * mBitmapWidth;
       float bimtapHeight = matrixValues[0] * mBitmapHeight;
       boolean in = newDist > oldDist;

       if(!in && matrixValues[0] < 1){
           return;
       }
       if(bitmapWidth > mViewWidth || bimtapHeight > mViewHeight){
           mDraggable = true;
       } else{
           mDraggable = false;
       }

       float midX = (mViewWidth / 2);
       float midY = (mViewHeight / 2);

       matrix.set(savedMatrix);
       scale = newDist / oldDist;
       matrix.postScale(scale, scale, bitmapWidth > mViewWidth ? mMiddlePoint.x : midX, bimtapHeight > mViewHeight ? mMiddlePoint.y : midY); 

       this.setImageMatrix(matrix);


   }





    /** Determine the space between the first two fingers */
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);

        return (float)Math.sqrt(x * x + y * y);
    }

    /** Calculate the mid point of the first two fingers */
    private void midPoint(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }


}
和布局:

<your.package.name.CustomImageVIew
        android:id="@+id/customImageVIew1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginBottom="15dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="15dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" 
        android:scaleType="matrix"/> // important
//重要

您可以使用此类:

在build.gradle中添加以下行:

compile 'com.commit451:PhotoView:1.2.4'

在Java文件中:

PhotoViewAttacher photoAttacher;
photoAttacher= new PhotoViewAttacher(Your_Image_View);
photoAttacher.update();
使用 学习新概念时,我不喜欢使用库或代码转储。我发现了一个很好的描述,以及如何通过挤压调整图像的大小。这个答案是一个稍加修改的摘要。您可能希望以后添加更多功能,但这将帮助您开始

布局
ImageView
仅使用应用程序徽标,因为它已经可用。不过,你可以用你喜欢的任何图像替换它

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_launcher"
        android:layout_centerInParent="true"/>

</RelativeLayout>
笔记
  • 尽管在上面的示例中,该活动具有手势检测器,但也可以在图像视图本身上进行设置
  • 您可以通过以下方式限制缩放的大小

    mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
    
  • 再次感谢

  • 使用Ctrl+鼠标拖动在模拟器中模拟挤压手势
进行中
您可能还想做其他事情,比如平移和缩放到某个焦点。您可以自己开发这些东西,但如果您想使用预先制作的自定义视图,请复制到您的项目中,并像普通的
ImageView
一样使用它。它对我很有效,我只遇到一个。我计划进一步编辑代码,删除警告和我不需要的部分。您也可以这样做。

我为imageview编写了代码,使用zoomageview通过收缩来缩放。因此用户可以将图像拖离屏幕,然后放大、缩小图像

您可以按照此
链接
逐步获取
代码以及给定的输出屏幕截图


Kotlin中的自定义缩放视图

 import android.content.Context
 import android.graphics.Matrix
 import android.graphics.PointF
 import android.util.AttributeSet
 import android.util.Log
 import android.view.MotionEvent
 import android.view.ScaleGestureDetector
 import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener
 import androidx.appcompat.widget.AppCompatImageView

 class ZoomImageview : AppCompatImageView {
var matri: Matrix? = null
var mode = NONE

// Remember some things for zooming
var last = PointF()
var start = PointF()
var minScale = 1f
var maxScale = 3f
lateinit var m: FloatArray
var viewWidth = 0
var viewHeight = 0
var saveScale = 1f
protected var origWidth = 0f
protected var origHeight = 0f
var oldMeasuredWidth = 0
var oldMeasuredHeight = 0
var mScaleDetector: ScaleGestureDetector? = null
var contex: Context? = null

constructor(context: Context) : super(context) {
    sharedConstructing(context)
}

constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
    sharedConstructing(context)
}

private fun sharedConstructing(context: Context) {
    super.setClickable(true)
    this.contex= context
    mScaleDetector = ScaleGestureDetector(context, ScaleListener())
    matri = Matrix()
    m = FloatArray(9)
    imageMatrix = matri
    scaleType = ScaleType.MATRIX
    setOnTouchListener { v, event ->
        mScaleDetector!!.onTouchEvent(event)
        val curr = PointF(event.x, event.y)
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                last.set(curr)
                start.set(last)
                mode = DRAG
            }
            MotionEvent.ACTION_MOVE -> if (mode == DRAG) {
                val deltaX = curr.x - last.x
                val deltaY = curr.y - last.y
                val fixTransX = getFixDragTrans(deltaX, viewWidth.toFloat(), origWidth * saveScale)
                val fixTransY = getFixDragTrans(deltaY, viewHeight.toFloat(), origHeight * saveScale)
                matri!!.postTranslate(fixTransX, fixTransY)
                fixTrans()
                last[curr.x] = curr.y
            }
            MotionEvent.ACTION_UP -> {
                mode = NONE
                val xDiff = Math.abs(curr.x - start.x).toInt()
                val yDiff = Math.abs(curr.y - start.y).toInt()
                if (xDiff < CLICK && yDiff < CLICK) performClick()
            }
            MotionEvent.ACTION_POINTER_UP -> mode = NONE
        }
        imageMatrix = matri
        invalidate()
        true // indicate event was handled
    }
}

fun setMaxZoom(x: Float) {
    maxScale = x
}

private inner class ScaleListener : SimpleOnScaleGestureListener() {
    override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
        mode = ZOOM
        return true
    }

    override fun onScale(detector: ScaleGestureDetector): Boolean {
        var mScaleFactor = detector.scaleFactor
        val origScale = saveScale
        saveScale *= mScaleFactor
        if (saveScale > maxScale) {
            saveScale = maxScale
            mScaleFactor = maxScale / origScale
        } else if (saveScale < minScale) {
            saveScale = minScale
            mScaleFactor = minScale / origScale
        }
        if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight) matri!!.postScale(mScaleFactor, mScaleFactor, viewWidth / 2.toFloat(), viewHeight / 2.toFloat()) else matri!!.postScale(mScaleFactor, mScaleFactor, detector.focusX, detector.focusY)
        fixTrans()
        return true
    }
}

fun fixTrans() {
    matri!!.getValues(m)
    val transX = m[Matrix.MTRANS_X]
    val transY = m[Matrix.MTRANS_Y]
    val fixTransX = getFixTrans(transX, viewWidth.toFloat(), origWidth * saveScale)
    val fixTransY = getFixTrans(transY, viewHeight.toFloat(), origHeight * saveScale)
    if (fixTransX != 0f || fixTransY != 0f) matri!!.postTranslate(fixTransX, fixTransY)
}

fun getFixTrans(trans: Float, viewSize: Float, contentSize: Float): Float {
    val minTrans: Float
    val maxTrans: Float
    if (contentSize <= viewSize) {
        minTrans = 0f
        maxTrans = viewSize - contentSize
    } else {
        minTrans = viewSize - contentSize
        maxTrans = 0f
    }
    if (trans < minTrans) return -trans + minTrans
    if (trans > maxTrans) return -trans + maxTrans
    return 0f
}

fun getFixDragTrans(delta: Float, viewSize: Float, contentSize: Float): Float {
    if (contentSize <= viewSize) {
        return 0f
    } else {
        return delta
    }
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    viewWidth = MeasureSpec.getSize(widthMeasureSpec)
    viewHeight = MeasureSpec.getSize(heightMeasureSpec)
    //
    // Rescales image on rotation
    //
    if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0) return
    oldMeasuredHeight = viewHeight
    oldMeasuredWidth = viewWidth
    if (saveScale == 1f) {
        //Fit to screen.
        val scale: Float
        val drawable = drawable
        if (drawable == null || drawable.intrinsicWidth == 0 || drawable.intrinsicHeight == 0) return
        val bmWidth = drawable.intrinsicWidth
        val bmHeight = drawable.intrinsicHeight
        Log.d("bmSize", "bmWidth: $bmWidth bmHeight : $bmHeight")
        val scaleX = viewWidth.toFloat() / bmWidth.toFloat()
        val scaleY = viewHeight.toFloat() / bmHeight.toFloat()
        scale = Math.min(scaleX, scaleY)
        matri!!.setScale(scale, scale)
        // Center the image
        var redundantYSpace = viewHeight.toFloat() - scale * bmHeight.toFloat()
        var redundantXSpace = viewWidth.toFloat() - scale * bmWidth.toFloat()
        redundantYSpace /= 2.toFloat()
        redundantXSpace /= 2.toFloat()
        matri!!.postTranslate(redundantXSpace, redundantYSpace)
        origWidth = viewWidth - 2 * redundantXSpace
        origHeight = viewHeight - 2 * redundantYSpace
        imageMatrix = matri
    }
    fixTrans()
}

companion object {
    // We can be in one of these 3 states
    const val NONE = 0
    const val DRAG = 1
    const val ZOOM = 2
    const val CLICK = 3
}
 }
导入android.content.Context
导入android.graphics.Matrix
导入android.graphics.PointF
导入android.util.AttributeSet
导入android.util.Log
导入android.view.MotionEvent
导入android.view.scalegestruedetector
导入android.view.scalegestruedetector.SimpleOnScalegestrueListener
导入androidx.appcompat.widget.AppCompatImageView
类ZoomImageview:AppCompatImageView{
变量矩阵:矩阵?=null
var模式=无
//记住一些关于缩放的事情
var last=PointF()
var start=PointF()
var minScale=1f
var maxScale=3f
lateinit var m:FloatArray
var viewWidth=0
var viewHeight=0
var saveScale=1f
受保护变量origWidth=0f
受保护的var origHeight=0f
var oldMeasuredWidth=0
var oldMeasuredHeight=0
var mScaleDetector:ScaleGetStureDetector?=null
var contex:上下文?=null
构造函数(上下文:上下文):超级(上下文){
共享构造(上下文)
}
构造函数(context:context,attrs:AttributeSet?):super(context,attrs){
共享构造(上下文)
}
私有趣味共享构造(上下文:上下文){
super.setClickable(真)
this.contex=context
mScaleDetector=scalegestruedetector(上下文,ScaleListener())
矩阵=矩阵()
m=浮点数组(9)
imageMatrix=matri
scaleType=scaleType.MATRIX
setOnTouchListener{v,事件->
mScaleDetector!!.onTouchEvent(事件)
val curr=PointF(event.x,event.y)
何时(事件、动作){
MotionEvent.ACTION\u向下->{
最后一组(当前)
开始。设置(最后一个)
模式=拖动
}
MotionEvent.ACTION\u MOVE->if(模式==拖动){
val deltaX=当前x-最后x
val deltaY=当前y-最后y
val fixtranx=getfixtragtrans(deltaX,viewWidth.toFloat(),origWidth*saveScale)
val fixTransY=getfixtragtrans(deltaY,viewHeight.toFloat(),origHeight*saveScale)
matri!!.postTranslate(fixtranx,fixtrany)
fixTrans()
最后一次[当前x]=当前
}
MotionEvent.ACTION\u UP->{
模式=无
val xDiff=Math.abs(curr.x-start.x).toInt()
val yDiff=Math.abs(curr.y-start.y).toInt()
if(xDiff模式=无
}
imageMatrix=matri
使无效
true//指示事件已处理
}
}
fun setMaxZoom(x:Float){
最大刻度=x
}
私有内部类ScaleListener:SimpleOnScaleGetStureListener(){
覆盖SCALEBEGIN(检测器:SCALEGSTUREDETECTOR):布尔值{
模式=缩放
返回真值
}
在刻度上覆盖乐趣(检测器:scalegestruedetector):布尔值{
var mScaleFactor=detector.scaleFactor
val origScale=saveScale
saveScale*=mScaleFactor
如果(保存比例>最大比例){
saveScale=maxScale
mScaleFactor=最大刻度/原始刻度
}else if(保存比例<最小比例){
saveScale=minScale
mScaleFactor=最小刻度/原始刻度
}

如果(origWidth*saveScale)您的意思是当您尝试收缩缩放时,您的图像也会改变位置。不完全是,在
ScaleListener.onScale()
中,我正在设置pivotPointX和Y,它们在
onDraw()矩阵.postScale中用作焦点(mScaleFactor,mScaleFactor,pivotPointX,pivotPo
PhotoViewAttacher photoAttacher;
photoAttacher= new PhotoViewAttacher(Your_Image_View);
photoAttacher.update();
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@mipmap/ic_launcher"
        android:layout_centerInParent="true"/>

</RelativeLayout>
public class MainActivity extends AppCompatActivity {

    private ScaleGestureDetector mScaleGestureDetector;
    private float mScaleFactor = 1.0f;
    private ImageView mImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // initialize the view and the gesture detector
        mImageView = findViewById(R.id.imageView);
        mScaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
    }

    // this redirects all touch events in the activity to the gesture detector
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return mScaleGestureDetector.onTouchEvent(event);
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

        // when a scale gesture is detected, use it to resize the image
        @Override
        public boolean onScale(ScaleGestureDetector scaleGestureDetector){
            mScaleFactor *= scaleGestureDetector.getScaleFactor();
            mImageView.setScaleX(mScaleFactor);
            mImageView.setScaleY(mScaleFactor);
            return true;
        }
    }
}
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
 import android.content.Context
 import android.graphics.Matrix
 import android.graphics.PointF
 import android.util.AttributeSet
 import android.util.Log
 import android.view.MotionEvent
 import android.view.ScaleGestureDetector
 import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener
 import androidx.appcompat.widget.AppCompatImageView

 class ZoomImageview : AppCompatImageView {
var matri: Matrix? = null
var mode = NONE

// Remember some things for zooming
var last = PointF()
var start = PointF()
var minScale = 1f
var maxScale = 3f
lateinit var m: FloatArray
var viewWidth = 0
var viewHeight = 0
var saveScale = 1f
protected var origWidth = 0f
protected var origHeight = 0f
var oldMeasuredWidth = 0
var oldMeasuredHeight = 0
var mScaleDetector: ScaleGestureDetector? = null
var contex: Context? = null

constructor(context: Context) : super(context) {
    sharedConstructing(context)
}

constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
    sharedConstructing(context)
}

private fun sharedConstructing(context: Context) {
    super.setClickable(true)
    this.contex= context
    mScaleDetector = ScaleGestureDetector(context, ScaleListener())
    matri = Matrix()
    m = FloatArray(9)
    imageMatrix = matri
    scaleType = ScaleType.MATRIX
    setOnTouchListener { v, event ->
        mScaleDetector!!.onTouchEvent(event)
        val curr = PointF(event.x, event.y)
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                last.set(curr)
                start.set(last)
                mode = DRAG
            }
            MotionEvent.ACTION_MOVE -> if (mode == DRAG) {
                val deltaX = curr.x - last.x
                val deltaY = curr.y - last.y
                val fixTransX = getFixDragTrans(deltaX, viewWidth.toFloat(), origWidth * saveScale)
                val fixTransY = getFixDragTrans(deltaY, viewHeight.toFloat(), origHeight * saveScale)
                matri!!.postTranslate(fixTransX, fixTransY)
                fixTrans()
                last[curr.x] = curr.y
            }
            MotionEvent.ACTION_UP -> {
                mode = NONE
                val xDiff = Math.abs(curr.x - start.x).toInt()
                val yDiff = Math.abs(curr.y - start.y).toInt()
                if (xDiff < CLICK && yDiff < CLICK) performClick()
            }
            MotionEvent.ACTION_POINTER_UP -> mode = NONE
        }
        imageMatrix = matri
        invalidate()
        true // indicate event was handled
    }
}

fun setMaxZoom(x: Float) {
    maxScale = x
}

private inner class ScaleListener : SimpleOnScaleGestureListener() {
    override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
        mode = ZOOM
        return true
    }

    override fun onScale(detector: ScaleGestureDetector): Boolean {
        var mScaleFactor = detector.scaleFactor
        val origScale = saveScale
        saveScale *= mScaleFactor
        if (saveScale > maxScale) {
            saveScale = maxScale
            mScaleFactor = maxScale / origScale
        } else if (saveScale < minScale) {
            saveScale = minScale
            mScaleFactor = minScale / origScale
        }
        if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight) matri!!.postScale(mScaleFactor, mScaleFactor, viewWidth / 2.toFloat(), viewHeight / 2.toFloat()) else matri!!.postScale(mScaleFactor, mScaleFactor, detector.focusX, detector.focusY)
        fixTrans()
        return true
    }
}

fun fixTrans() {
    matri!!.getValues(m)
    val transX = m[Matrix.MTRANS_X]
    val transY = m[Matrix.MTRANS_Y]
    val fixTransX = getFixTrans(transX, viewWidth.toFloat(), origWidth * saveScale)
    val fixTransY = getFixTrans(transY, viewHeight.toFloat(), origHeight * saveScale)
    if (fixTransX != 0f || fixTransY != 0f) matri!!.postTranslate(fixTransX, fixTransY)
}

fun getFixTrans(trans: Float, viewSize: Float, contentSize: Float): Float {
    val minTrans: Float
    val maxTrans: Float
    if (contentSize <= viewSize) {
        minTrans = 0f
        maxTrans = viewSize - contentSize
    } else {
        minTrans = viewSize - contentSize
        maxTrans = 0f
    }
    if (trans < minTrans) return -trans + minTrans
    if (trans > maxTrans) return -trans + maxTrans
    return 0f
}

fun getFixDragTrans(delta: Float, viewSize: Float, contentSize: Float): Float {
    if (contentSize <= viewSize) {
        return 0f
    } else {
        return delta
    }
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    viewWidth = MeasureSpec.getSize(widthMeasureSpec)
    viewHeight = MeasureSpec.getSize(heightMeasureSpec)
    //
    // Rescales image on rotation
    //
    if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight || viewWidth == 0 || viewHeight == 0) return
    oldMeasuredHeight = viewHeight
    oldMeasuredWidth = viewWidth
    if (saveScale == 1f) {
        //Fit to screen.
        val scale: Float
        val drawable = drawable
        if (drawable == null || drawable.intrinsicWidth == 0 || drawable.intrinsicHeight == 0) return
        val bmWidth = drawable.intrinsicWidth
        val bmHeight = drawable.intrinsicHeight
        Log.d("bmSize", "bmWidth: $bmWidth bmHeight : $bmHeight")
        val scaleX = viewWidth.toFloat() / bmWidth.toFloat()
        val scaleY = viewHeight.toFloat() / bmHeight.toFloat()
        scale = Math.min(scaleX, scaleY)
        matri!!.setScale(scale, scale)
        // Center the image
        var redundantYSpace = viewHeight.toFloat() - scale * bmHeight.toFloat()
        var redundantXSpace = viewWidth.toFloat() - scale * bmWidth.toFloat()
        redundantYSpace /= 2.toFloat()
        redundantXSpace /= 2.toFloat()
        matri!!.postTranslate(redundantXSpace, redundantYSpace)
        origWidth = viewWidth - 2 * redundantXSpace
        origHeight = viewHeight - 2 * redundantYSpace
        imageMatrix = matri
    }
    fixTrans()
}

companion object {
    // We can be in one of these 3 states
    const val NONE = 0
    const val DRAG = 1
    const val ZOOM = 2
    const val CLICK = 3
}
 }