Android图像视图捏缩放

我正在使用多点触控的缩放图像视图的代码示例。 在ScaleListener上,我添加了ScaleGestureDetector.getFocusX() and 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); 
 @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub ImageView view = (ImageView) v; dumpEvent(event); // Handle touch events here... switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); start.set(event.getX(), event.getY()); Log.d(TAG, "mode=DRAG"); mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; Log.d(TAG, "mode=ZOOM"); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; Log.d(TAG, "mode=NONE"); break; case MotionEvent.ACTION_MOVE: if (mode == DRAG) { // ... matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x, event.getY() - start.y); } else if (mode == ZOOM) { float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 10f) { matrix.set(savedMatrix); float scale = newDist / oldDist; matrix.postScale(scale, scale, mid.x, mid.y); } } break; } view.setImageMatrix(matrix); return true; } private void dumpEvent(MotionEvent event) { String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" }; StringBuilder sb = new StringBuilder(); int action = event.getAction(); int actionCode = action & MotionEvent.ACTION_MASK; sb.append("event ACTION_").append(names[actionCode]); if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) { sb.append("(pid ").append( action >> MotionEvent.ACTION_POINTER_ID_SHIFT); sb.append(")"); } sb.append("["); for (int i = 0; i < event.getPointerCount(); i++) { sb.append("#").append(i); sb.append("(pid ").append(event.getPointerId(i)); sb.append(")=").append((int) event.getX(i)); sb.append(",").append((int) event.getY(i)); if (i + 1 < event.getPointerCount()) sb.append(";"); } sb.append("]"); Log.d(TAG, sb.toString()); } /** 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 FloatMath.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); } 

不要忘记将scaleType属性设置为ImageView标记的matrix,如:

 <ImageView android:id="@+id/imageEnhance" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginBottom="15dp" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_marginTop="15dp" android:background="@drawable/enhanceimageframe" android:scaleType="matrix" > </ImageView> 

和使用的variables是:

 // 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; 

你可以使用这个类: TouchImageView

我做了我自己的自定义imageview与捏缩放。 Chirag Raval的代码没有限制/边界,所以用户可以将图像拖出屏幕。 这将解决它。

这里是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); } } 

这是你如何在你的活动中使用它:

 CustomImageVIew mImageView = (CustomImageVIew)findViewById(R.id.customImageVIew1); mImage.setBitmap(your bitmap); 

和布局:

 <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' 

要么

 compile 'com.github.chrisbanes:PhotoView:1.3.0' 

在Java文件中:

 PhotoViewAttacher photoAttacher; photoAttacher= new PhotoViewAttacher(Your_Image_View); photoAttacher.update();