【Android開發小記--9】觸控事件---實現雙指縮放圖片
阿新 • • 發佈:2019-01-30
關於觸控事件
覆寫 onTouchEvent(MotionEvent event) 方法:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: break; } //以下三種效果都是一樣的 System.out.println(event.getAction()); /*老寫法*/ System.out.println(event.getActionMasked());/*API 8 以後,Google推薦*/ System.out.println(MotionEventCompat.getActionMasked(event)); /*相容寫法*/ //獲取螢幕上的手指數 System.out.println(MotionEventCompat.getPointerCount(event)); //觸點座標 int actionIndex = MotionEventCompat.getActionIndex(event); //多點觸控 if (MotionEventCompat.getPointerCount(event) > 1) { float touchX_1 = MotionEventCompat.getX(event, 0); float touchY_1 = MotionEventCompat.getY(event, 0); float touchX_2 = MotionEventCompat.getX(event, 1); float touchY_2 = MotionEventCompat.getY(event, 1); System.out.println(String.format("touchX_1:%f,touchY_1:%f,touchX_2:%f,touchY_2:%f\n", touchX_1, touchY_1, touchX_2, touchY_2)); } else { //單點觸控 float touchX = MotionEventCompat.getX(event, actionIndex); float touchY = MotionEventCompat.getY(event, actionIndex); System.out.println(touchX + "\t" + touchY); } return super.onTouchEvent(event); }
getAction、getActionMask、getActionIndex區別:
Android用一個32位的整型值表示一次TouchEvent事件,低8位表示touch事件的具體動作,比如按下,擡起,滑動,還有多點觸控時的按下,擡起,這個和單點是區分開的,下面看具體的方法:1 getAction:觸控動作的原始32位資訊,包括事件的動作,觸控點資訊
2 getActionMask:觸控的動作,按下,擡起,滑動,多點按下,多點擡起
3 getActionIndex:觸控點資訊
Matrix 中的post 和pre 和set 方法的區別 以及Canvas中的方法:
post pre set 其實代表了Matrix 中方法變換的次序,pre是向前加入佇列執行,post從後面加入佇列執行, 而matrix的set方法則會對先前的pre和post操作進行清除,而後再設定它的值。雙指縮放圖片,並且帶拖動回彈居中的效果
這裡是使用 Matrix +Bitmap 來進行圖片縮放的。
首先,要對佈局檔案中的 ImageView 設定:
android:scaleType="matrix"
在 MainActivity.java 中,呼叫 Matrix 的 setScale()、postTranslate()、postScale() 方法來設定圖片的移動方式,再呼叫 ImageView 的 setImageMatrix():
public class MainActivity extends AppCompatActivity { private ImageView imageView; private int screenWidth, screenHeight;//螢幕寬高 private Bitmap bitmap; private Matrix matrix = new Matrix(); private Matrix savedMatrix = new Matrix(); private int mode = 0; private float distance; private float preDistance; private PointF mid = new PointF();//兩指中點 Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = MainActivity.this; imageView = (ImageView) findViewById(R.id.imageView); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); matrix.setScale(0.5f, 0.5f); //顯示先縮小一些 center();//縮小後居中 imageView.setImageMatrix(matrix); imageView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v; switch (event.getAction() & MotionEvent.ACTION_MASK) { //單個手指觸控 case MotionEvent.ACTION_DOWN: mode = 1; break; //兩指觸控 case MotionEvent.ACTION_POINTER_DOWN: preDistance = getDistance(event); //當兩指間距大於10時,計算兩指中心點 if (preDistance > 10f) { mid = getMid(event); savedMatrix.set(matrix); mode = 2; } break; case MotionEvent.ACTION_UP: mode = 0; break; case MotionEvent.ACTION_POINTER_UP: mode = 0; break; case MotionEvent.ACTION_MOVE: //當兩指縮放,計算縮放比例 if (mode == 2) { distance = getDistance(event); if (distance > 10f) { matrix.set(savedMatrix); float scale = distance / preDistance; matrix.postScale(scale, scale, mid.x, mid.y);//縮放比例和中心點座標 } } break; } view.setImageMatrix(matrix); center(); //回彈,令圖片居中 return true; } }); } /*獲取兩指之間的距離*/ private float getDistance(MotionEvent event) { float x = event.getX(1) - event.getX(0); float y = event.getY(1) - event.getY(0); float distance = (float) Math.sqrt(x * x + y * y);//兩點間的距離 return distance; } /*使圖片居中*/ private void center() { Matrix m = new Matrix(); m.set(matrix); //繪製圖片矩形 //這樣rect.left,rect.right,rect.top,rect.bottom分別就就是當前螢幕離圖片的邊界的距離 RectF rect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()); m.mapRect(rect); float height = rect.height(); float width = rect.width(); float deltaX = 0, deltaY = 0; //螢幕的寬高 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); //獲取螢幕解析度 screenWidth = dm.widthPixels; //螢幕寬度 screenHeight = dm.heightPixels; //螢幕高度 //獲取ActionBar的高度 int actionBarHeight = 0; TypedValue tv = new TypedValue(); if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); } //計算Y到中心的距離 if (height < screenHeight) { deltaY = (screenHeight - height) / 2 - rect.top - actionBarHeight; } else if (rect.top > 0) { deltaY = -rect.top; } else if (rect.bottom < screenHeight) { deltaY = imageView.getHeight() - rect.bottom; } //計算X到中心的距離 if (width < screenWidth) { deltaX = (screenWidth - width) / 2 - rect.left; } else if (rect.left > 0) { deltaX = -rect.left; } else if (rect.right < screenWidth) { deltaX = screenWidth - rect.right; } matrix.postTranslate(deltaX, deltaY); } /*取兩指的中心點座標*/ public static PointF getMid(MotionEvent event) { float midX = (event.getX(1) + event.getX(0)) / 2; float midY = (event.getY(1) + event.getY(0)) / 2; return new PointF(midX, midY); } }
這裡,令圖片居中的 center() 方法:
1.使用Bitmap來獲取圖片的寬高,再使用矩形 RectF ,以及 Matrix 的 mapRect()方法來得到當前圖片的位置;
2.獲取螢幕寬高,以及Actionbar的高度;
3.再計算圖片中心點到螢幕中心點的距離,進行平移;