第三部分 應用
在這一部分,我們會將前面兩部分所瞭解到的內容和Android手勢結合起來,利用各種不同的手勢對映像進行平移、縮放和旋轉,前面兩項都是在實踐中經常需要用到的功能,後一項據說蘋果也是最近才加上的,而實際上在Android中,咱們通過自己的雙手,也可以很輕鬆地實現之。
首先建立一個Android項目PatImageView,同時建立一個Activity:PatImageViewActivity。完成這一步後, 記得在AndroidManifest.xml中增加如下許可:
<uses-permissionandroid:name="android.permission.VIBRATE"/>
因為我們將要通過短按還是長按,來確定將圖片到底是縮放還是旋轉。
現在來建立一個ImageView的衍生類別:PatImageView,其代碼(PatImageView.java)如下(2011-11-22 revised):
package com.pat.imageview;import android.app.Service;import android.content.Context;import android.graphics.Matrix;import android.graphics.PointF;import android.os.Vibrator;import android.util.FloatMath;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.View;import android.widget.ImageView;public class PatImageView extends ImageView{private Matrix matrix;private Matrix savedMatrix;private boolean long_touch = false;private static int NONE = 0;private static int DRAG = 1;// 拖動private static int ZOOM = 2;// 縮放private static int ROTA = 3;// 旋轉private int mode = NONE;private PointF startPoint;private PointF middlePoint;private float oldDistance;private float oldAngle;private Vibrator vibrator;private GestureDetector gdetector;public PatImageView(final Context context){super(context);matrix = new Matrix();savedMatrix = new Matrix();matrix.setTranslate(0f, 0f);setScaleType(ScaleType.MATRIX);setImageMatrix(matrix);startPoint = new PointF();middlePoint = new PointF();oldDistance = 1f;gdetector = new GestureDetector(context, new GestureDetector.OnGestureListener(){@Overridepublic boolean onSingleTapUp(MotionEvent e){return true;}@Overridepublic void onShowPress(MotionEvent e){}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){return true;}@Overridepublic void onLongPress(MotionEvent e){long_touch = true;vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);// 震動50ms,提示後續的操作將是旋轉圖片,而非縮放圖片vibrator.vibrate(50);}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY){return true;}@Overridepublic boolean onDown(MotionEvent e){return true;}});setOnTouchListener(new OnTouchListener(){public boolean onTouch(View view, MotionEvent event){switch(event.getAction() & MotionEvent.ACTION_MASK){case MotionEvent.ACTION_DOWN:// 第一個手指touchsavedMatrix.set(matrix);startPoint.set(event.getX(), event.getY());mode = DRAG;long_touch = false;break;case MotionEvent.ACTION_POINTER_DOWN:// 第二個手指toucholdDistance = getDistance(event);// 計算第二個手指touch時,兩指之間的距離oldAngle = getDegree(event);// 計算第二個手指touch時,兩指所形成的直線和x軸的角度if(oldDistance > 10f){savedMatrix.set(matrix);middlePoint = midPoint(event);if(!long_touch){mode = ZOOM;}else{mode = ROTA;}}break;case MotionEvent.ACTION_UP:mode = NONE;break;case MotionEvent.ACTION_POINTER_UP:mode = NONE;break;case MotionEvent.ACTION_MOVE:if(vibrator != null)vibrator.cancel();if(mode == DRAG){matrix.set(savedMatrix);matrix.postTranslate(event.getX() - startPoint.x, event.getY() - startPoint.y);}if(mode == ZOOM){float newDistance = getDistance(event);if(newDistance > 10f){matrix.set(savedMatrix);float scale = newDistance / oldDistance;matrix.postScale(scale, scale, middlePoint.x, middlePoint.y);}}if(mode == ROTA){float newAngle = getDegree(event);matrix.set(savedMatrix);float degrees = newAngle - oldAngle;matrix.postRotate(degrees, middlePoint.x, middlePoint.y);}break;}setImageMatrix(matrix);invalidate();gdetector.onTouchEvent(event);return true;}});}// 計算兩個手指之間的距離 private float getDistance(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); } // 計算兩個手指所形成的直線和x軸的角度 private float getDegree(MotionEvent event) { return (float)(Math.atan((event.getY(1) - event.getY(0)) / (event.getX(1) - event.getX(0))) * 180f); } // 計算兩個手指之間,中間點的座標 private PointF midPoint( MotionEvent event) { PointF point = new PointF(); float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); return point; }}
下面完善PatImageViewActivity.java的代碼,使之如下:
package com.pat.imageview;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.view.Window;import android.view.WindowManager;public class PatImageViewActivity extends Activity{ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); PatImageView piv = new PatImageView(this); Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.sophie); piv.setImageBitmap(bmp); setContentView(piv); }}
由於有些手勢在模擬器上無法類比,所以就不上運行結果的圖片了。本人在真機上運行後(照片就不拍了,有點累啦),可以輕鬆做到:
1. 很方便地拖動圖片(比如,單指按住螢幕進行拖動)
2. 很方便地縮放圖片(比如,雙指按住螢幕進行分開或者併攏操作,可分別實現放大或者縮小圖片的功能)
3. 長按出現震動後,可以很方便地旋轉圖片(一個手指固定,另外一個手指圍繞那個固定的手指運動)。