Android實(shí)現(xiàn)手勢(shì)控制ImageView圖片大小
本文實(shí)例實(shí)現(xiàn)的主要功能是在ImageView中識(shí)別手勢(shì)用以控制圖片放大或縮小,具有一定的參考價(jià)值,分享給大家。
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);
}
}
我對(duì)其中定義OnSingleTapListener接口的方法稍作了一些修改,為onSingleTap回調(diào)方法增加了MotionEvent類(lèi)型的參數(shù),來(lái)方便我們根據(jù)用戶具體的事件內(nèi)容作出對(duì)應(yīng)的控制。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家學(xué)習(xí)Android軟件編程有所幫助。
- Android手勢(shì)ImageView三部曲 第二部
- Android手勢(shì)ImageView三部曲 第一部
- Android自定義GestureDetector實(shí)現(xiàn)手勢(shì)ImageView
- Android使用ImageView實(shí)現(xiàn)支持手勢(shì)縮放效果
- Android ImageView隨手勢(shì)變化動(dòng)態(tài)縮放圖片
- Android手勢(shì)滑動(dòng)實(shí)現(xiàn)ImageView縮放圖片大小
- Android通過(guò)手勢(shì)實(shí)現(xiàn)的縮放處理實(shí)例代碼
- android開(kāi)發(fā)之為activity增加左右手勢(shì)識(shí)別示例
- android使用gesturedetector手勢(shì)識(shí)別示例分享
- Android手勢(shì)ImageView三部曲 第三部
相關(guān)文章
淺析Android位置權(quán)限以及數(shù)組尋找索引的坑
這篇文章給大家分享了Android位置權(quán)限以及數(shù)組尋找索引的坑的相關(guān)知識(shí)點(diǎn)內(nèi)容,有興趣的朋友可以參考學(xué)習(xí)下。2018-07-07
Android使用SwipeListView實(shí)現(xiàn)類(lèi)似QQ的滑動(dòng)刪除效果
這篇文章主要介紹了Android使用SwipeListView實(shí)現(xiàn)類(lèi)似QQ的滑動(dòng)刪除效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
Android開(kāi)發(fā)之SeekBar基本使用及各種美觀樣式示例
這篇文章主要介紹了Android開(kāi)發(fā)之SeekBar基本使用及各種美觀樣式,結(jié)合實(shí)例形式分析了Android SeekBar控件的功能及樣式改變相關(guān)操作技巧,需要的朋友可以參考下2019-03-03
flutter?material?widget組件之信息展示組件使用詳解
這篇文章主要為大家詳細(xì)介紹了flutter?material?widget組件之信息展示組件的使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Android編程創(chuàng)建桌面快捷方式的常用方法小結(jié)【2種方法】
這篇文章主要介紹了Android編程創(chuàng)建桌面快捷方式的常用方法,結(jié)合實(shí)例形式總結(jié)分析了2種常見(jiàn)的實(shí)現(xiàn)方法與相關(guān)操作技巧,需要的朋友可以參考下2017-02-02
Android實(shí)現(xiàn)登錄注冊(cè)界面框架
這篇文章主要介紹了Android實(shí)現(xiàn)登錄注冊(cè)界面的框架,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
Android開(kāi)發(fā)學(xué)習(xí)路線圖
這篇文章主要介紹了Android開(kāi)發(fā)學(xué)習(xí)路線圖,本文從基礎(chǔ)、入門(mén)、進(jìn)階、高級(jí)等4個(gè)方面鋪開(kāi)學(xué)習(xí)路線圖,需要的朋友可以參考下2015-04-04
Android 手動(dòng)獲取判斷處理權(quán)限
本篇文章主要介紹了Android手動(dòng)獲取判斷處理權(quán)限的方法,具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-05-05

