Android ImageView缩放和翻译问题

我正在开发一个Android应用程序(API 19 4.4),我遇到了ImageViews的一些问题。 我有一个SurfaceView,我在其中dynamic添加我想对触摸事件作出反应的ImageViews。 到目前为止,我已经设法使ImageView平稳移动,但我有一个恼人的行为。

当我缩小图像到一定的限制(我会说原始大小的一半),我试图移动它,图像闪烁。 经过短暂的分析,似乎在屏幕上的手指点周围对称地切换其位置,并累积距离,最后看不见(发生的很快(<1s)),我认为我错过了与亲戚触摸事件的值ImageView / SurfaceView,但我是一个相当小白,我被困住了…

这是我的代码

public class MyImageView extends ImageView { private ScaleGestureDetector mScaleDetector ; private static final int MAX_SIZE = 1024; private static final String TAG = "MyImageView"; PointF DownPT = new PointF(); // Record Mouse Position When Pressed Down PointF StartPT = new PointF(); // Record Start Position of 'img' public MyImageView(Context context) { super(context); mScaleDetector = new ScaleGestureDetector(context,new MySimpleOnScaleGestureListener()); setBackgroundColor(Color.RED); setScaleType(ScaleType.MATRIX); setAdjustViewBounds(true); RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); lp.setMargins(-MAX_SIZE, -MAX_SIZE, -MAX_SIZE, -MAX_SIZE); this.setLayoutParams(lp); this.setX(MAX_SIZE); this.setY(MAX_SIZE); } int firstPointerID; boolean inScaling=false; @Override public boolean onTouchEvent(MotionEvent event) { // get pointer index from the event object int pointerIndex = event.getActionIndex(); // get pointer ID int pointerId = event.getPointerId(pointerIndex); //First send event to scale detector to find out, if it's a scale boolean res = mScaleDetector.onTouchEvent(event); if (!mScaleDetector.isInProgress()) { int eid = event.getAction(); switch (eid & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_MOVE : if(pointerId == firstPointerID) { PointF mv = new PointF( (int)(event.getX() - DownPT.x), (int)( event.getY() - DownPT.y)); this.setX((int)(StartPT.x+mv.x)); this.setY((int)(StartPT.y+mv.y)); StartPT = new PointF( this.getX(), this.getY() ); } break; case MotionEvent.ACTION_DOWN : { firstPointerID = pointerId; DownPT.x = (int) event.getX(); DownPT.y = (int) event.getY(); StartPT = new PointF( this.getX(), this.getY() ); break; } case MotionEvent.ACTION_POINTER_DOWN: { break; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_CANCEL: { firstPointerID = -1; break; } default : break; } return true; } return true; } public boolean onScaling(ScaleGestureDetector detector) { this.setScaleX(this.getScaleX()*detector.getScaleFactor()); this.setScaleY(this.getScaleY()*detector.getScaleFactor()); invalidate(); return true; } private class MySimpleOnScaleGestureListener extends SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { return onScaling(detector); } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { Log.d(TAG, "onScaleBegin"); return true; } @Override public void onScaleEnd(ScaleGestureDetector arg0) { Log.d(TAG, "onScaleEnd"); } } 

}

我还有一个关于轮换的问题。 我应该如何执行这个? 我可以用某种方式使用ScalegestureDetector,还是让我在视图触摸事件中使用这个工作? 我希望能够以相同的手势进行缩放和旋转(并移动到另一个手势)。

感谢帮助我,我真的很感激!

对不起我的英语不好

这是两个手指移动/缩放/旋转的工作示例(注意:由于使用了智能检测器,代码非常短 – 请参阅MatrixGestureDetector ):

 class ViewPort extends View { List<Layer> layers = new LinkedList<Layer>(); int[] ids = {R.drawable.layer0, R.drawable.layer1, R.drawable.layer2}; public ViewPort(Context context) { super(context); Resources res = getResources(); for (int i = 0; i < ids.length; i++) { Layer l = new Layer(context, this, BitmapFactory.decodeResource(res, ids[i])); layers.add(l); } } @Override protected void onDraw(Canvas canvas) { for (Layer l : layers) { l.draw(canvas); } } private Layer target; @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { target = null; for (int i = layers.size() - 1; i >= 0; i--) { Layer l = layers.get(i); if (l.contains(event)) { target = l; layers.remove(l); layers.add(l); invalidate(); break; } } } if (target == null) { return false; } return target.onTouchEvent(event); } } class Layer implements MatrixGestureDetector.OnMatrixChangeListener { Matrix matrix = new Matrix(); Matrix inverse = new Matrix(); RectF bounds; View parent; Bitmap bitmap; MatrixGestureDetector mgd = new MatrixGestureDetector(matrix, this); public Layer(Context ctx, View p, Bitmap b) { parent = p; bitmap = b; bounds = new RectF(0, 0, b.getWidth(), b.getHeight()); matrix.postTranslate(50 + (float) Math.random() * 50, 50 + (float) Math.random() * 50); } public boolean contains(MotionEvent event) { matrix.invert(inverse); float[] pts = {event.getX(), event.getY()}; inverse.mapPoints(pts); if (!bounds.contains(pts[0], pts[1])) { return false; } return Color.alpha(bitmap.getPixel((int) pts[0], (int) pts[1])) != 0; } public boolean onTouchEvent(MotionEvent event) { mgd.onTouchEvent(event); return true; } @Override public void onChange(Matrix matrix) { parent.invalidate(); } public void draw(Canvas canvas) { canvas.drawBitmap(bitmap, matrix, null); } } class MatrixGestureDetector { private static final String TAG = "MatrixGestureDetector"; private int ptpIdx = 0; private Matrix mTempMatrix = new Matrix(); private Matrix mMatrix; private OnMatrixChangeListener mListener; private float[] mSrc = new float[4]; private float[] mDst = new float[4]; private int mCount; interface OnMatrixChangeListener { void onChange(Matrix matrix); } public MatrixGestureDetector(Matrix matrix, MatrixGestureDetector.OnMatrixChangeListener listener) { this.mMatrix = matrix; this.mListener = listener; } public void onTouchEvent(MotionEvent event) { if (event.getPointerCount() > 2) { return; } int action = event.getActionMasked(); int index = event.getActionIndex(); switch (action) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: int idx = index * 2; mSrc[idx] = event.getX(index); mSrc[idx + 1] = event.getY(index); mCount++; ptpIdx = 0; break; case MotionEvent.ACTION_MOVE: for (int i = 0; i < mCount; i++) { idx = ptpIdx + i * 2; mDst[idx] = event.getX(i); mDst[idx + 1] = event.getY(i); } mTempMatrix.setPolyToPoly(mSrc, ptpIdx, mDst, ptpIdx, mCount); mMatrix.postConcat(mTempMatrix); if(mListener != null) { mListener.onChange(mMatrix); } System.arraycopy(mDst, 0, mSrc, 0, mDst.length); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: if (event.getPointerId(index) == 0) ptpIdx = 2; mCount--; break; } } } 

我终于使用这个(间距是用来计算两个手指之间的距离),我抵消缩放后的imageview保持居中,现在工作正常:

  float newDist = spacing(event); float scale = newDist / oldDist; int oldH =getLayoutParams().height; int oldW =getLayoutParams().width; int newH =(int) (getLayoutParams().height*scale); int newW =(int) (getLayoutParams().width*scale); if(newH<MAX_SIZE && newW<MAX_SIZE){ //scale the height and width of the view getLayoutParams().height = newH; getLayoutParams().width = newW; //calculate the X and Y offset to apply after scaling to keep the image centered int xOffset = (int)(getLayoutParams().height - oldH)/2; int yOffset = (int)(getLayoutParams().width - oldW)/2; setX(getX()-xOffset); setY(getY()-yOffset); requestLayout(); setAdjustViewBounds(true); oldDist=newDist; 

我试图实现多点触摸不使用matrix的位图,现在我成功了。 现在,我认为这将有助于您为多个图像的个人手势。 试试吧,它对我最好。

 public class MultiTouchImageView extends ImageView implements OnTouchListener{ float[] lastEvent = null; float d = 0f; float newRot = 0f; public static String fileNAME; public static int framePos = 0; //private ImageView view; private boolean isZoomAndRotate; private boolean isOutSide; // We can be in one of these 3 states private static final int NONE = 0; private static final int DRAG = 1; private static final int ZOOM = 2; private int mode = NONE; private PointF start = new PointF(); private PointF mid = new PointF(); float oldDist = 1f; public MultiTouchImageView(Context context) { super(context); } public MultiTouchImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MultiTouchImageView(Context context, AttributeSet attrs) { super(context, attrs); } @SuppressWarnings("deprecation") @Override public boolean onTouch(View v, MotionEvent event) { //view = (ImageView) v; bringToFront(); // Handle touch events here... switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: //savedMatrix.set(matrix); start.set(event.getX(), event.getY()); mode = DRAG; lastEvent = null; break; case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); if (oldDist > 10f) { midPoint(mid, event); mode = ZOOM; } lastEvent = new float[4]; lastEvent[0] = event.getX(0); lastEvent[1] = event.getX(1); lastEvent[2] = event.getY(0); lastEvent[3] = event.getY(1); d = rotation(event); break; case MotionEvent.ACTION_UP: isZoomAndRotate = false; case MotionEvent.ACTION_OUTSIDE: isOutSide = true; mode = NONE; lastEvent = null; case MotionEvent.ACTION_POINTER_UP: mode = NONE; lastEvent = null; break; case MotionEvent.ACTION_MOVE: if(!isOutSide){ if (mode == DRAG && !isZoomAndRotate) { isZoomAndRotate = false; setTranslationX((event.getX() - start.x) + getTranslationX()); setTranslationY((event.getY() - start.y) + getTranslationY()); } else if (mode == ZOOM && event.getPointerCount() == 2) { isZoomAndRotate = true; boolean isZoom = false; if(!isRotate(event)){ float newDist = spacing(event); if (newDist > 10f) { float scale = newDist / oldDist * getScaleX(); setScaleX(scale); setScaleY(scale); isZoom = true; } } else if(!isZoom){ newRot = rotation(event); setRotation((float)(getRotation() + (newRot - d))); } } } break; } new GestureDetector(new MyGestureDectore()); Constants.currentSticker = this; return true; } private class MyGestureDectore extends GestureDetector.SimpleOnGestureListener{ @Override public boolean onDoubleTap(MotionEvent e) { bringToFront(); return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { return false; } } private float rotation(MotionEvent event) { double delta_x = (event.getX(0) - event.getX(1)); double delta_y = (event.getY(0) - event.getY(1)); double radians = Math.atan2(delta_y, delta_x); return (float) Math.toDegrees(radians); } 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); } 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); } private boolean isRotate(MotionEvent event){ int dx1 = (int) (event.getX(0) - lastEvent[0]); int dy1 = (int) (event.getY(0) - lastEvent[2]); int dx2 = (int) (event.getX(1) - lastEvent[1]); int dy2 = (int) (event.getY(1) - lastEvent[3]); Log.d("dx1 ", ""+ dx1); Log.d("dx2 ", "" + dx2); Log.d("dy1 ", "" + dy1); Log.d("dy2 ", "" + dy2); //pointer 1 if(Math.abs(dx1) > Math.abs(dy1) && Math.abs(dx2) > Math.abs(dy2)) { if(dx1 >= 2.0 && dx2 <= -2.0){ Log.d("first pointer ", "right"); return true; } else if(dx1 <= -2.0 && dx2 >= 2.0){ Log.d("first pointer ", "left"); return true; } } else { if(dy1 >= 2.0 && dy2 <= -2.0){ Log.d("seccond pointer ", "top"); return true; } else if(dy1 <= -2.0 && dy2 >= 2.0){ Log.d("second pointer ", "bottom"); return true; } } return false; } }