本文实例实现的主要功能是在ImageView中识别手势用以控制图片放大或缩小,具有一定的参考价值,分享给大家。
public class MatrixImageView extends ImageView {
private GestureDetector mGestureDetector;
private Matrix mMatrix = new Matrix();
private float mImageWidth;
private float mImageHeight;
private float mScale;
private OnMovingListener mMoveListener;
private OnSingleTapListener mSingleTapListener;
public MatrixImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MatrixImageView(Context context) {
super(context, null);
init();
}
private void init() {
MatrixTouchListener listener = new MatrixTouchListener();
setOnTouchListener(listener);
mGestureDetector = new GestureDetector(getContext(),
new GestureListener(listener));
setBackgroundColor(Color.BLACK);
setScaleType(ScaleType.FIT_CENTER);
}
public void setOnMovingListener(OnMovingListener listener) {
mMoveListener = listener;
}
public void setOnSingleTapListener(OnSingleTapListener onSingleTapListener) {
this.mSingleTapListener = onSingleTapListener;
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
if (getWidth() == 0) {
ViewTreeObserver vto = getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
initData();
MatrixImageView.this.getViewTreeObserver()
.removeOnPreDrawListener(this);
return true;
}
});
} else {
initData();
}
}
private void initData() {
mMatrix.set(getImageMatrix());
float[] values = new float[9];
mMatrix.getValues(values);
mImageWidth = getWidth() / values[Matrix.MSCALE_X];
mImageHeight = (getHeight() - values[Matrix.MTRANS_Y] * 2)
/ values[Matrix.MSCALE_Y];
mScale = values[Matrix.MSCALE_X];
}
public class MatrixTouchListener implements OnTouchListener {
private static final int MODE_DRAG = 1;
private static final int MODE_ZOOM = 2;
private static final int MODE_UNABLE = 3;
private static final float MAX_SCALE = 6;
private static final float DOUBLE_CLICK_SACLE = 2;
private int mMode = 0;
private float mStartDis;
private Matrix mCurrentMatrix = new Matrix();
private boolean mLeftDragable;
private boolean mRightDragable;
private boolean mFirstMove = false;
private PointF mStartPoint = new PointF();
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mMode = MODE_DRAG;
mStartPoint.set(event.getX(), event.getY());
isMatrixEnable();
startDrag();
checkDragable();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
reSetMatrix();
stopDrag();
break;
case MotionEvent.ACTION_MOVE:
if (mMode == MODE_ZOOM) {
setZoomMatrix(event);
} else if (mMode == MODE_DRAG) {
setDragMatrix(event);
} else {
stopDrag();
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
if (mMode == MODE_UNABLE)
return true;
mMode = MODE_ZOOM;
mStartDis = distance(event);
break;
case MotionEvent.ACTION_POINTER_UP:
break;
default:
break;
}
return mGestureDetector.onTouchEvent(event);
}
private void startDrag() {
if (mMoveListener != null)
mMoveListener.startDrag();
}
private void stopDrag() {
if (mMoveListener != null)
mMoveListener.stopDrag();
}
private void checkDragable() {
mLeftDragable = true;
mRightDragable = true;
mFirstMove = true;
float[] values = new float[9];
getImageMatrix().getValues(values);
if (values[Matrix.MTRANS_X] >= 0)
mRightDragable = false;
if ((mImageWidth) * values[Matrix.MSCALE_X]
+ values[Matrix.MTRANS_X] <= getWidth()) {
mLeftDragable = false;
}
}
public void setDragMatrix(MotionEvent event) {
if (isZoomChanged()) {
float dx = event.getX() - mStartPoint.x;
float dy = event.getY() - mStartPoint.y;
if (Math.sqrt(dx * dx + dy * dy) > 10f) {
mStartPoint.set(event.getX(), event.getY());
mCurrentMatrix.set(getImageMatrix());
float[] values = new float[9];
mCurrentMatrix.getValues(values);
dy = checkDyBound(values, dy);
dx = checkDxBound(values, dx, dy);
mCurrentMatrix.postTranslate(dx, dy);
setImageMatrix(mCurrentMatrix);
}
} else {
stopDrag();
}
}
private boolean isZoomChanged() {
float[] values = new float[9];
getImageMatrix().getValues(values);
float scale = values[Matrix.MSCALE_X];
return scale != mScale;
}
private float checkDyBound(float[] values, float dy) {
float height = getHeight();
if (mImageHeight * values[Matrix.MSCALE_Y] < height)
return 0;
if (values[Matrix.MTRANS_Y] + dy > 0)
dy = -values[Matrix.MTRANS_Y];
else if (values[Matrix.MTRANS_Y] + dy < -(mImageHeight
* values[Matrix.MSCALE_Y] - height))
dy = -(mImageHeight * values[Matrix.MSCALE_Y] - height)
- values[Matrix.MTRANS_Y];
return dy;
}
private float checkDxBound(float[] values, float dx, float dy) {
float width = getWidth();
if (!mLeftDragable && dx < 0) {
if (Math.abs(dx) * 0.4f > Math.abs(dy) && mFirstMove) {
stopDrag();
}
return 0;
}
if (!mRightDragable && dx > 0) {
if (Math.abs(dx) * 0.4f > Math.abs(dy) && mFirstMove) {
stopDrag();
}
return 0;
}
mLeftDragable = true;
mRightDragable = true;
if (mFirstMove)
mFirstMove = false;
if (mImageWidth * values[Matrix.MSCALE_X] < width) {
return 0;
}
if (values[Matrix.MTRANS_X] + dx > 0) {
dx = -values[Matrix.MTRANS_X];
} else if (values[Matrix.MTRANS_X] + dx < -(mImageWidth
* values[Matrix.MSCALE_X] - width)) {
dx = -(mImageWidth * values[Matrix.MSCALE_X] - width)
- values[Matrix.MTRANS_X];
}
return dx;
}
private void setZoomMatrix(MotionEvent event) {
if (event.getPointerCount() < 2)
return;
float endDis = distance(event);
if (endDis > 10f) {
float scale = endDis / mStartDis;
mStartDis = endDis;
mCurrentMatrix.set(getImageMatrix());
float[] values = new float[9];
mCurrentMatrix.getValues(values);
scale = checkMaxScale(scale, values);
PointF centerF = getCenter(scale, values);
mCurrentMatrix.postScale(scale, scale, centerF.x, centerF.y);
setImageMatrix(mCurrentMatrix);
}
}
private PointF getCenter(float scale, float[] values) {
if (scale * values[Matrix.MSCALE_X] < mScale || scale >= 1) {
return new PointF(getWidth() / 2, getHeight() / 2);
}
float cx = getWidth() / 2;
float cy = getHeight() / 2;
if ((getWidth() / 2 - values[Matrix.MTRANS_X]) * scale < getWidth() / 2)
cx = 0;
if ((mImageWidth * values[Matrix.MSCALE_X] + values[Matrix.MTRANS_X])
* scale < getWidth())
cx = getWidth();
return new PointF(cx, cy);
}
private float checkMaxScale(float scale, float[] values) {
if (scale * values[Matrix.MSCALE_X] > MAX_SCALE)
scale = MAX_SCALE / values[Matrix.MSCALE_X];
return scale;
}
private void reSetMatrix() {
if (checkRest()) {
mCurrentMatrix.set(mMatrix);
setImageMatrix(mCurrentMatrix);
} else {
float[] values = new float[9];
getImageMatrix().getValues(values);
float height = mImageHeight * values[Matrix.MSCALE_Y];
if (height < getHeight()) {
float topMargin = (getHeight() - height) / 2;
if (topMargin != values[Matrix.MTRANS_Y]) {
mCurrentMatrix.set(getImageMatrix());
mCurrentMatrix.postTranslate(0, topMargin
- values[Matrix.MTRANS_Y]);
setImageMatrix(mCurrentMatrix);
}
}
}
}
private boolean checkRest() {
float[] values = new float[9];
getImageMatrix().getValues(values);
float scale = values[Matrix.MSCALE_X];
return scale < mScale;
}
private void isMatrixEnable() {
if (getScaleType() != ScaleType.CENTER) {
setScaleType(ScaleType.MATRIX);
} else {
mMode = MODE_UNABLE;
}
}
private float distance(MotionEvent event) {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getY(0);
return (float) Math.sqrt(dx * dx + dy * dy);
}
public void onDoubleClick() {
float scale = isZoomChanged() ? 1 : DOUBLE_CLICK_SACLE;
mCurrentMatrix.set(mMatrix);
mCurrentMatrix.postScale(scale, scale, getWidth() / 2,
getHeight() / 2);
setImageMatrix(mCurrentMatrix);
}
}
private class GestureListener extends SimpleOnGestureListener {
private final MatrixTouchListener mTouchListener;
public GestureListener(MatrixTouchListener listener) {
this.mTouchListener = listener;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
mTouchListener.onDoubleClick();
return true;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return super.onSingleTapUp(e);
}
@Override
public void onLongPress(MotionEvent e) {
super.onLongPress(e);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return super.onScroll(e1, e2, distanceX, distanceY);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return super.onFling(e1, e2, velocityX, velocityY);
}
@Override
public void onShowPress(MotionEvent e) {
super.onShowPress(e);
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
return super.onDoubleTapEvent(e);
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (mSingleTapListener != null)
mSingleTapListener.onSingleTap(e);
return super.onSingleTapConfirmed(e);
}
}
public interface OnMovingListener {
public void startDrag();
public void stopDrag();
}
public interface OnSingleTapListener {
public void onSingleTap(MotionEvent e);
}
}
我对其中定义OnSingleTapListener接口的方法稍作了一些修改,为onSingleTap回调方法增加了MotionEvent类型的参数,来方便我们根据用户具体的事件内容作出对应的控制。
您可能感兴趣的文章:Android手势ImageView三部曲 第二部Android手势ImageView三部曲 第一部Android自定义GestureDetector实现手势ImageViewAndroid使用ImageView实现支持手势缩放效果Android ImageView随手势变化动态缩放图片Android手势滑动实现ImageView缩放图片大小Android通过手势实现的缩放处理实例代码android开发之为activity增加左右手势识别示例android使用gesturedetector手势识别示例分享Android手势ImageView三部曲 第三部