1. 程式人生 > >【Android開發小記--9】觸控事件---實現雙指縮放圖片

【Android開發小記--9】觸控事件---實現雙指縮放圖片

關於觸控事件

覆寫 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.再計算圖片中心點到螢幕中心點的距離,進行平移;