Android實(shí)現(xiàn)手勢控制ImageView圖片大小
本文實(shí)例實(shí)現(xiàn)的主要功能是在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回調(diào)方法增加了MotionEvent類型的參數(shù),來方便我們根據(jù)用戶具體的事件內(nèi)容作出對應(yīng)的控制。
以上就是本文的全部內(nèi)容,希望對大家學(xué)習(xí)Android軟件編程有所幫助。
- Android手勢ImageView三部曲 第二部
- Android手勢ImageView三部曲 第一部
- Android自定義GestureDetector實(shí)現(xiàn)手勢ImageView
- Android使用ImageView實(shí)現(xiàn)支持手勢縮放效果
- Android ImageView隨手勢變化動態(tài)縮放圖片
- Android手勢滑動實(shí)現(xiàn)ImageView縮放圖片大小
- Android通過手勢實(shí)現(xiàn)的縮放處理實(shí)例代碼
- android開發(fā)之為activity增加左右手勢識別示例
- android使用gesturedetector手勢識別示例分享
- Android手勢ImageView三部曲 第三部
相關(guān)文章
淺析Android位置權(quán)限以及數(shù)組尋找索引的坑
這篇文章給大家分享了Android位置權(quán)限以及數(shù)組尋找索引的坑的相關(guān)知識點(diǎn)內(nèi)容,有興趣的朋友可以參考學(xué)習(xí)下。2018-07-07
Android使用SwipeListView實(shí)現(xiàn)類似QQ的滑動刪除效果
這篇文章主要介紹了Android使用SwipeListView實(shí)現(xiàn)類似QQ的滑動刪除效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-08-08
Android開發(fā)之SeekBar基本使用及各種美觀樣式示例
這篇文章主要介紹了Android開發(fā)之SeekBar基本使用及各種美觀樣式,結(jié)合實(shí)例形式分析了Android SeekBar控件的功能及樣式改變相關(guān)操作技巧,需要的朋友可以參考下2019-03-03
flutter?material?widget組件之信息展示組件使用詳解
這篇文章主要為大家詳細(xì)介紹了flutter?material?widget組件之信息展示組件的使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08
Android編程創(chuàng)建桌面快捷方式的常用方法小結(jié)【2種方法】
這篇文章主要介紹了Android編程創(chuàng)建桌面快捷方式的常用方法,結(jié)合實(shí)例形式總結(jié)分析了2種常見的實(shí)現(xiàn)方法與相關(guān)操作技巧,需要的朋友可以參考下2017-02-02

