Android實(shí)現(xiàn)手勢控制ImageView圖片大小
本文實(shí)例實(shí)現(xiàn)的主要功能是在ImageView中識(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);
}
}
我對其中定義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隨手勢變化動(dòng)態(tài)縮放圖片
- Android手勢滑動(dòng)實(shí)現(xiàn)ImageView縮放圖片大小
- Android通過手勢實(shí)現(xiàn)的縮放處理實(shí)例代碼
- android開發(fā)之為activity增加左右手勢識(shí)別示例
- android使用gesturedetector手勢識(shí)別示例分享
- Android手勢ImageView三部曲 第三部
相關(guān)文章
Android Camera2采集攝像頭原始數(shù)據(jù)
這篇文章主要介紹了Android Camera2采集攝像頭原始數(shù)據(jù)并進(jìn)行手工預(yù)覽的功能實(shí)現(xiàn)原理以及代碼分析,需要的朋友學(xué)習(xí)下吧。2018-02-02
Android自定義view實(shí)現(xiàn)雪花特效實(shí)例代碼
實(shí)現(xiàn)雪花的效果其實(shí)也可以通過自定義View的方式來實(shí)現(xiàn)的,而且操作上也相對簡單一些,下面這篇文章主要給大家介紹了關(guān)于Android自定義view實(shí)現(xiàn)雪花特效的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12
Android 滑動(dòng)定位和吸附懸停效果實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 滑動(dòng)定位和吸附懸停效果實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
Android實(shí)現(xiàn)兩臺(tái)手機(jī)屏幕共享和遠(yuǎn)程控制功能
在遠(yuǎn)程協(xié)助、在線教學(xué)、技術(shù)支持等多種場景下,實(shí)時(shí)獲得另一部移動(dòng)設(shè)備的屏幕畫面,并對其進(jìn)行操作,具有極高的應(yīng)用價(jià)值,本項(xiàng)目旨在實(shí)現(xiàn)兩臺(tái) Android 手機(jī)之間的屏幕共享與遠(yuǎn)程控制,需要的朋友可以參考下2025-04-04
詳解Android中的ActivityThread和APP啟動(dòng)過程
ActivityThread就是我們常說的主線程或UI線程,ActivityThread的main方法是整個(gè)APP的入口,本篇深入學(xué)習(xí)下ActivityThread,順便了解下APP和Activity的啟動(dòng)過程。2021-06-06
Android 進(jìn)度條按鈕ProgressButton的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 進(jìn)度條按鈕實(shí)現(xiàn)(ProgressButton)代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2018-10-10
Android Studio 3.0 Gradle 配置變更
這篇文章主要介紹了Android Studio 3.0 Gradle 配置變更的相關(guān)知識(shí),即多渠道打包變更和更改打包命名及路徑的代碼,感興趣的朋友跟隨腳本之家小編一起看看吧2018-03-03

