国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android手勢ImageView三部曲 第一部

2019-12-12 03:28:30
字體:
來源:轉載
供稿:網友

這幾天一直在研究github上的PhotoView跟GestureImageView,發現寫的都很牛,看了很久的代碼,于是打算把自己所看的一些東西總結一下,內容還是很多的,但是很有含金量哈~~

先附上兩個開源項目的鏈接:

GestureImageView: https://github.com/jasonpolites/gesture-imageview

PhotoView:https://github.com/chrisbanes/PhotoView

這樣說有點乏味哈,先看看我們今天要實現的效果:

當一個手指按住圖片的時候,此時的效果為拖拽的效果。
當兩個手指按住圖片的時候,手指旋轉則圖片跟著旋轉,手指縮放則圖片縮放。
效果圖大致為(我模擬器不太好模擬旋轉):

這里寫圖片描述

好了下面我們來實現一下這個手勢縮放ImageView:

首先我們創建一個叫MatrixImageView的類去繼承ImageView,然后重寫其構造方法(我就不考慮直接new的情況了哈):

public class MatrixImageView2 extends ImageView { public MatrixImageView2(Context context, AttributeSet attrs) {  super(context, attrs);  initView(); }}

然后我們需要定義幾種當前view的狀態:
MODE_NONE(初始狀態);
MODE_DRAG(拖拽狀態);
MODE_ZOOM(兩個手指縮放狀態)

public class MatrixImageView2 extends ImageView { private static final int MODE_NONE = 190; private static final int MODE_DRAG = 468; private static final int MODE_ZOOM = 685; .....}

我們對ImageView做旋轉、縮放、位移等操作主要是用到ImageView的這個方法:

 /**  * Adds a transformation {@link Matrix} that is applied  * to the view's drawable when it is drawn. Allows custom scaling,  * translation, and perspective distortion.  *  * @param matrix the transformation parameters in matrix form  */ public void setImageMatrix(Matrix matrix) {  // collapse null and identity to just null  if (matrix != null && matrix.isIdentity()) {   matrix = null;  }  // don't invalidate unless we're actually changing our matrix  if (matrix == null && !mMatrix.isIdentity() ||    matrix != null && !mMatrix.equals(matrix)) {   mMatrix.set(matrix);   configureBounds();   invalidate();  } }

利用的是Matrix這個類(對這個類不懂的童鞋自己去查資料哈~),然后通過監聽我們的onTouchEvent方法獲取當前手勢操作,然后對matrix進行相應操作,改變圖片的狀態。

代碼比較短,而且我每行都注釋了,我就直接給代碼了:

MatrixImageView.java:

package com.leo.gestureimageview;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.widget.ImageView;public class MatrixImageView2 extends ImageView { private static final int MODE_NONE = 190; private static final int MODE_DRAG = 468; private static final int MODE_ZOOM = 685; //當前mode private int mode; //手指按下時候的坐標 private float startX, startY; //兩個手指中間點的位置 private float midX, midY; //當前imageview的matirx對象,以前imageview的matrix對象 private Matrix currMatrix, savedMatrix; //之前圖片的旋轉角度 private float preRotate; //之間兩個手指之間的距離 private float preSpacing; public MatrixImageView2(Context context, AttributeSet attrs) {  super(context, attrs);  initView(); } private void initView() {  //初始化模式為初始狀態  mode = MODE_NONE;  currMatrix = new Matrix();  savedMatrix = new Matrix();  DisplayMetrics dm = getResources().getDisplayMetrics();  //給ImageView設置一張圖片(此處為了測試直接在imageview里面設置了一張測試圖片)  Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test);  bitmap = Bitmap.createScaledBitmap(bitmap, dm.widthPixels, dm.heightPixels, true);  setImageBitmap(bitmap); } @Override public boolean onTouchEvent(MotionEvent event) {  //多點觸碰如果需要監聽ACTION_POINTER_DOWN等操作的時候,必須用event.getAction() & MotionEvent.ACTION_MASK  //而不是直接的event.getAction();  switch (event.getAction() & MotionEvent.ACTION_MASK) {   //當一個手指按下的時候   case MotionEvent.ACTION_DOWN:    //保存當前imageview的matrix對象    savedMatrix.set(currMatrix);    //記錄手指開始的坐標    startX = event.getX();    startY = event.getY();    //此時的狀態為拖拽狀態    mode = MODE_DRAG;    break;   //當兩個手指按下的時候(我們先不考慮很多個的情況哈,能力有限~!)   case MotionEvent.ACTION_POINTER_DOWN:    //計算兩個手指之間的距離并保存起來    preSpacing = calSpacing(event);    //如果兩個手指之間的距離大于我們指定的一個值后(改變狀態為縮放)    if (preSpacing > 10f) {     savedMatrix.set(currMatrix);     mode = MODE_ZOOM;     //記錄下縮放的中間坐標值     midX = (event.getX(0) + event.getX(1)) / 2;     midY = (event.getY(0) + event.getY(1)) / 2;    }    //根據兩個手指的位置計算出當前角度并保存    preRotate = calRotate(event);    break;   //當手指移動的時候   case MotionEvent.ACTION_MOVE:    //如果之前給的狀態為拖拽狀態的時候    if (mode == MODE_DRAG) {     //首先把之前的matrix的狀態賦給當前的matrix對象     currMatrix.set(savedMatrix);     //算出手指移動的距離     float dx = event.getX() - startX;     float dy = event.getY() - startY;     //把手指移動的距離設置給matrix對象     currMatrix.postTranslate(dx, dy);     //當狀態為放大狀態的時候,并且有兩個手指按下的時候    } else if (mode == MODE_ZOOM && event.getPointerCount() == 2) {     //首先把之前的matrix的狀態賦給當前的matrix對象     currMatrix.set(savedMatrix);     //計算出此時兩個手指之間的距離     float spacing = calSpacing(event);     //如果此時兩手指之間的距離大于我們給定的值     if (spacing > 10f) {      //此時兩手指距離/第二個手指剛按下時兩手指的距離      float scale = spacing / preSpacing;      //把算出的縮放值給當前matrix對象,(縮放中心點為之前算出的mid)      currMatrix.postScale(scale, scale, midX, midY);     }     //根據兩手指位置算出此時的旋轉角度     float rotate = calRotate(event);     if (rotate != preRotate) {      //算出此時需要旋轉的角度      rotate = rotate - preRotate;      //開始旋轉圖片      currMatrix.postRotate(rotate, getMeasuredWidth() / 2, getMeasuredHeight() / 2);     }    }    break;  }  //最后記得把當前的matrix對象給imageview  setImageMatrix(currMatrix);  return true; } /**  * 根據兩手指的位置算出角度  * 勾股定理 tan0=x(兩手指橫坐標距離)/y(兩手指縱坐標距離);  * @param event  * @return  */ private float calRotate(MotionEvent event) {  double x = event.getX(0) - event.getX(1);  double y = event.getY(0) - event.getY(1);  double radius = Math.atan2(y, x);  return (float) Math.toDegrees(radius); } /**  * 兩個點距離公式為d*d=(x1-x0)的平方+(y1-y0)的平方  * @param event  * @return  */ private float calSpacing(MotionEvent event) {  float x = event.getX(0) - event.getX(1);  float y = event.getY(0) - event.getY(1);  return (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); }}

然后添加我們的布局文件:

 <com.leo.gestureimageview.MatrixImageView  android:layout_width="match_parent"  android:layout_height="match_parent"  android:scaleType="matrix"  android:src="@mipmap/test"  />

最后運行代碼:

這里寫圖片描述

好了,雖說我們是實現了我們的手勢imageview的基本功能,但是如果要處理那種多點(>兩個手指)觸碰,還有一些復雜的操作的時候,我們的onTouchEvent里面寫的代碼可能就不止這么一點了(還是有點復雜的,考慮的因素太多),但如果可以把某個事件的處理單獨拿出去分成很多個分支的話,還會這么復雜么?? 如果說我們的代碼可以像下面這樣的話,你是不是覺得很爽呢?

package com.leo.gestureimageview;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.graphics.PointF;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.view.ScaleGestureDetector;import android.widget.ImageView;import com.leo.gestureimageview.GestureDetectors.MoveGestureDetector;import com.leo.gestureimageview.GestureDetectors.RotateGestureDetector;public class MatrixImageView2 extends ImageView { private Matrix mMatrix = new Matrix(); private float mScaleFactor =1f; private float mRotationDegrees = 0.f; private float mFocusX = 0.f; private float mFocusY = 0.f; private ScaleGestureDetector mScaleDetector; private RotateGestureDetector mRotateDetector; private MoveGestureDetector mMoveDetector; public MatrixImageView2(Context context, AttributeSet attrs) { super(context, attrs); initView(); } private void initView() { //初始化模式為初始狀態 DisplayMetrics dm = getResources().getDisplayMetrics(); //給ImageView設置一張圖片(此處為了測試直接在imageview里面設置了一張測試圖片) Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.test); bitmap = Bitmap.createScaledBitmap(bitmap, dm.widthPixels, dm.heightPixels, true); setImageBitmap(bitmap); mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); mRotateDetector = new RotateGestureDetector(getContext(), new RotateListener()); mMoveDetector = new MoveGestureDetector(getContext(), new MoveListener()); mFocusX = dm.widthPixels/2f; mFocusY = dm.heightPixels/2f; } @Override public boolean onTouchEvent(MotionEvent event) { mScaleDetector.onTouchEvent(event); mRotateDetector.onTouchEvent(event); mMoveDetector.onTouchEvent(event); return true; } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) {  mScaleFactor *= detector.getScaleFactor(); // scale change since previous event  // Don't let the object get too small or too large.  mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));  changeMatrix();  return true; } } private class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener { @Override public boolean onRotate(RotateGestureDetector detector) {  mRotationDegrees -= detector.getRotationDegreesDelta();  changeMatrix();  return true; } } private class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener { @Override public boolean onMove(MoveGestureDetector detector) {  PointF d = detector.getFocusDelta();  mFocusX += d.x;  mFocusY += d.y;  changeMatrix();  return true; } } private void changeMatrix(){ float scaledImageCenterX = (getDrawable().getIntrinsicWidth()*mScaleFactor)/2; float scaledImageCenterY = (getDrawable().getIntrinsicHeight()*mScaleFactor)/2; mMatrix.reset(); mMatrix.postScale(mScaleFactor, mScaleFactor); mMatrix.postRotate(mRotationDegrees, scaledImageCenterX, scaledImageCenterY); mMatrix.postTranslate(mFocusX - scaledImageCenterX, mFocusY - scaledImageCenterY); setImageMatrix(mMatrix); }}

我們的ImageView的onTouchEvent就只剩下短短的幾行代碼了,然后各個detector處理完事件后,我們只需要拿到處理好的值就可以了:

 @Override public boolean onTouchEvent(MotionEvent event) { //把縮放事件給mScaleDetector mScaleDetector.onTouchEvent(event); //把旋轉事件個mRotateDetector mRotateDetector.onTouchEvent(event); //把移動事件給mMoveDetector mMoveDetector.onTouchEvent(event); return true; }

是不是覺得很爽呢? 是的,我也是無意中看到了這個開源項目,先附上這個框架的github鏈接:
https://github.com/Almeros/android-gesture-detectors

下一節我們將深入了解detector,以及系統自帶的手勢處理工具類GestureDetector,感興趣的小伙伴請繼續關注哦。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 醴陵市| 科尔| 德惠市| 水富县| 黔西县| 博罗县| 慈利县| 田阳县| 涞水县| 永德县| 五华县| 仁化县| 防城港市| 容城县| 武安市| 新晃| 沙雅县| 土默特左旗| 青州市| 临城县| 宜昌市| 秀山| 荆门市| 五台县| 凤山县| 昭觉县| 莆田市| 泾源县| 高阳县| 平谷区| 镇赉县| 天台县| 鞍山市| 竹北市| 页游| 高青县| 阿克苏市| 平江县| 龙陵县| 肃南| 科尔|