GestureDetector和ScaleGestureDetector示例

/**
 * 演示【单点触摸手势识别器】
 * 演示【缩放手势识别器】最简单的使用
 * @author 白乾涛
 */
public class FirstActivity extends Activity implements OnTouchListener {
    private ImageView iv;
    private GestureDetector mGestureDetector;//单击和双击事件手势识别器
    private ScaleGestureDetector mScaleGestureDetector;//缩放事件手势识别器
    private Matrix matrix = new Matrix();
    private DecimalFormat df = new DecimalFormat("0.00");//格式化float
    private float lastScale = 1;//记录上次的缩放比例,下次缩放时是在此基础上进行的
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        iv = new ImageView(this);
        iv.setImageResource(R.drawable.ic_launcher);
        iv.setScaleType(ScaleType.MATRIX);//用矩阵来绘制
        setContentView(iv);
        mGestureDetector = new GestureDetector(this, new MyGestureListener());
        mScaleGestureDetector = new ScaleGestureDetector(this, new SimpleOnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                float scale = detector.getScaleFactor(); //缩放因子,两指靠拢时小于1
                float x = detector.getFocusX(), y = detector.getFocusY();//中心点坐标
                Log.i("bqt", "缩放手势  onScale," + df.format(scale) + "-" + df.format(x) + "-" + df.format(y));
                matrix.setScale(lastScale * scale, lastScale * scale);
                iv.setImageMatrix(matrix);
                return super.onScale(detector);
            }
            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                Log.i("bqt", "缩放手势  onScaleBegin," + df.format(detector.getScaleFactor()));//始终是1
                return super.onScaleBegin(detector);
            }
            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                super.onScaleEnd(detector);
                lastScale *= detector.getScaleFactor();
                Log.i("bqt", "缩放手势  onScaleEnd," + df.format(detector.getScaleFactor()));
            }
        });
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        mScaleGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return false;//设置OnTouchListener时,返回值要为false,或者在onTouch()中将MotionEvent事件传给GestureDetector,才能使手势识别器生效
    }
    class MyGestureListener extends SimpleOnGestureListener {
        @Override
        //双击的【第二下】Touch down时触发(只执行一次)
        public boolean onDoubleTap(MotionEvent e) {
            Log.i("bqt", "onDoubleTap");
            return super.onDoubleTap(e);
        }
        @Override
        //双击的【第二下】Touch down和up都会触发(执行次数不确定)。 
        public boolean onDoubleTapEvent(MotionEvent e) {
            Log.i("bqt", "onDoubleTapEvent");
            return super.onDoubleTapEvent(e);
        }
        @Override
        //Touch down时触发
        public boolean onDown(MotionEvent e) {
            Log.i("bqt", "onDown");
            return super.onDown(e);
        }
        @Override
        //onScroll一点距离后,【抛掷时】触发(若是轻轻的、慢慢的停止活动,而非抛掷,则很可能不触发)
        //参数为手指接触屏幕、离开屏幕一瞬间的动作事件,及手指水平、垂直方向移动的速度,像素/秒
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            Log.i("bqt", "onFling");
            if ((e2.getRawX() - e1.getRawX()) > 100) {
                Log.i("bqt", "onFling-从左到右滑");
                return true;//消耗事件
            }
            return super.onFling(e1, e2, velocityX, velocityY);
        }
        @Override
        //Touch了不移动一直Touch down时触发 
        public void onLongPress(MotionEvent e) {
            Log.i("bqt", "onLongPress");
            super.onLongPress(e);
        }
        @Override
        //Touch了滑动时触发,e1代表触摸时的事件,是不变的,e2代表滑动过程中的事件,是时刻变化的
        //distance是当前event2与上次回调时的event2之间的距离,代表上次回调之后到这次回调之前移动的距离
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            Log.i("bqt", "onScroll-" + (int) e1.getX() + "-" + (int) e2.getX() + "-" + (int) distanceX + "-" + (int) distanceY);
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
        @Override
        //Touch了还没有滑动时触发 
        public void onShowPress(MotionEvent e) {
            Log.i("bqt", "onShowPress");
            super.onShowPress(e);
        }
        @Override
        //在touch down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touchup时触发。
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Log.i("bqt", "onSingleTapConfirmed");
            return super.onSingleTapConfirmed(e);
        }
        @Override
        //在touch down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touchup时触发。
        public boolean onSingleTapUp(MotionEvent e) {
            Log.i("bqt", "onSingleTapUp");
            return super.onSingleTapUp(e);
        }
    }

}


MotionEvent示例:缩放图片

public class SecondActivity extends Activity implements OnTouchListener {
    private ImageView iv;
    private float scale = 1;
    private float lastScale = 1;//记录手指全部离开时的缩放比例,下次缩放时是在此基础上进行的
    private float oldDist;//记录第二个触摸点和第一个触摸点之间的距离 
    private Matrix mMatrix = new Matrix();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        iv = new ImageView(this);
        iv.setImageResource(R.drawable.ic_launcher);
        iv.setBackgroundColor(0x8822ffff);//从背景可以看出,此ImageView 是占用整个屏幕大小的
        iv.setScaleType(ScaleType.MATRIX);
        iv.setOnTouchListener(this);
        setContentView(iv);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            Log.i("bqt", "ACTION_DOWN,第一个触摸点,所以肯定为【1】" + event.getPointerCount());
            break;
        case MotionEvent.ACTION_UP://当屏幕上唯一的点被放开时触发
            lastScale = scale;//记录手指全部离开时的缩放比例,下次缩放时是在此基础上进行的
            Log.i("bqt", "ACTION_UP,最后一个触摸点,之前触摸点数肯定为【1】" + event.getPointerCount());
            break;
        case MotionEvent.ACTION_POINTER_UP://当屏幕上有多个点被按住,松开其中一个点时触发
            Log.i("bqt", "ACTION_POINTER_UP,少一个触摸点,少之前的触摸点数为" + event.getPointerCount());
            break;
        case MotionEvent.ACTION_POINTER_DOWN://当屏幕上已经有一个点被按住,此时再按下其他点时触发
            if (event.getPointerCount() == 2) oldDist = spacing(event);//记录第二个触摸点和第一个触摸点之间的距离 
            Log.i("bqt", "ACTION_POINTER_DOWN,又一个触摸点,目前触摸点数为" + event.getPointerCount());
            break;
        case MotionEvent.ACTION_MOVE://当有点在屏幕上移动时触发
            if (event.getPointerCount() == 2) {
                float newDist = spacing(event);//移动过程中,第二个点和第一个点的距离 
                if (Math.abs(newDist - oldDist) > 10) {//减小灵敏度
                    scale = lastScale * newDist / oldDist;
                    Log.i("bqt", "ACTION_MOVE,缩放比例为" + scale);
                    mMatrix.setScale(scale, scale);
                    iv.setImageMatrix(mMatrix);
                }
            }
            break;
        }
        return true;
    }
    /**
     * 返回两个点之间的距离
     */
    private float spacing(MotionEvent event) {
        if (event.getPointerCount() >= 2) {
            float x = event.getX(0) - event.getX(1);
            float y = event.getY(0) - event.getY(1);
            return (float) Math.sqrt(x * x + y * y);
        } else return 0;
    }

}


MotionEvent示例:功能增强

public class ThirdActivity extends Activity implements OnTouchListener {
    private ImageView imageView;
    private Matrix startMatrix = new Matrix();//ImageView初始矩阵
    private Matrix matrix = new Matrix();//要给ImageView设置的矩阵
    private float startDis;//两个手指的按下时的初始距离
    private PointF midPoint;//两个手指的按下时中间点
    private PointF startPoint = new PointF();//第一个手指按下时的坐标位置
    private boolean isPointerUp;//当有手指放开时,如果不停止缩放,会导致图片位置错乱。后续可以优化
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        imageView = new ImageView(this);
        imageView.setImageResource(R.drawable.ic_launcher);
        imageView.setOnTouchListener(this);
        imageView.setScaleType(ScaleType.MATRIX);
        setContentView(imageView);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            Log.i("bqt", "初始矩阵" + imageView.getImageMatrix());//值是会变的 {[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}
            startMatrix.set(imageView.getImageMatrix());//获取初始状态
            startPoint.set(event.getX(), event.getY());//获取开始时候的坐标位置
            isPointerUp = true;
            break;
        case MotionEvent.ACTION_MOVE:
            if (isPointerUp) {
                if (event.getPointerCount() == 1) { //移动图片
                    float dx = event.getX() - startPoint.x; // 得到X轴的移动距离
                    float dy = event.getY() - startPoint.y; // 得到Y轴的移动距离
                    Log.i("bqt", "移动距离" + (int) dx + "---" + (int) dy);
                    matrix.set(startMatrix);//先置为初始状态
                    matrix.postTranslate(dx, dy);
                } else if (event.getPointerCount() == 2) { // 放大缩小图片
                    float endDis = distance(event);// 距离
                    float scale = endDis / startDis;//ImageView缩放的比例
                    Log.i("bqt", "缩放倍数" + scale);
                    matrix.set(startMatrix);
                    matrix.postScale(scale, scale, midPoint.x, midPoint.y);
                }
                imageView.setImageMatrix(matrix);
            }
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            startDis = distance(event);
            midPoint = mid(event);
            startMatrix.set(imageView.getImageMatrix());//重置为目前的初始状态
            break;
        case MotionEvent.ACTION_UP:
            break;
        case MotionEvent.ACTION_POINTER_UP:
            isPointerUp = false;
            break;
        }
        return true;
    }
    /** 计算两个手指间的距离 */
    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);
    }
    /** 计算两个手指间的中间点 */
    private PointF mid(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);
    }

}


附件列表

手势 触摸【缩放】GestureDetector MotionEvent 案例的更多相关文章

  1. android131 360 05 手势触摸滑动,sim卡,开机启动的广播,手机联系人,SharedPreferences,拦截短信

    安卓手势触摸滑动: package com.itheima52.mobilesafe.activity; import android.app.Activity; import android.con ...

  2. 手势监听GestureDetector 案例

    以下只做长按和甩出(用户按下朝某一方向甩动手指)案例 OnGestureListener可以查看到更多的手势事件 案例 package com.qf.mobliesafe.activity; impo ...

  3. 触摸事件 Touch MotionEvent ACTION

    MotionEvent简介 当用户触摸屏幕时,将创建一个MontionEvent对象,MotionEvent包含了关于发生触摸的位置.时间信息,以及触摸事件的其他细节. 获取MontionEvent对 ...

  4. Android 手势&触摸事件

    在刚开始学Android的时候,就觉得Google的文档不咋样,在研究手势时,更加的感觉Google的文档写得实在是太差了.很多常量,属性和方法,居然连个描述都没有. 没有描述也就罢了,但是OnGes ...

  5. 手势交互之GestureDetector

    GsetureDetector 一.交互过程 触屏的一刹那,触发MotionEvent事件 被OnTouchListener监听,在onTouch()中获得MotionEvent对象 GestureD ...

  6. Android多点触摸缩放图片-android学习之旅(四)

    获取多触摸点 核心代码: 获取触摸点的个数和位置 public boolean onTouch(View v, MotionEvent event) { switch (event.getAction ...

  7. 触摸事件【MotionEvent】简介

    MotionEvent简介 当用户触摸屏幕时,将创建一个MontionEvent对象,MotionEvent包含了关于发生触摸的位置.时间信息,以及触摸事件的其他很多细节. Android 将所有的输 ...

  8. WebBrowser禁用触摸缩放

    最近做一个WPF触屏的项目,引用到WebBrowser控件,由于是触屏的所以控件里的网页可以缩放,客户提出要求,屏蔽这缩放功能. 于是网上找了很多资料,也换过控件,WebView2 控件使用Micro ...

  9. canvas学习笔记(下篇) -- canvas入门教程--保存状态/变形/旋转/缩放/矩阵变换/综合案例(星空/时钟/小球)

    [下篇] -- 建议学习时间4小时  课程共(上中下)三篇 此笔记是我初次接触canvas的时候的学习笔记,这次特意整理为博客供大家入门学习,几乎涵盖了canvas所有的基础知识,并且有众多练习案例, ...

随机推荐

  1. vs.net 效率提升-自定义快捷键

    工欲善其事必先利其器,记录一下自己开发时常用的几个自定义的快捷键.做了这么多年了用着还是比较顺手的分享下~~~~设置时有时设置不成功,非得一项一项设置才可以~~~ 设置自定义快捷键位置:vs.net- ...

  2. Android之 解析XML文件(1)—— Pull解析

    (以下文章基本照抄<第一行代码>) 解析XML文件有很多方法,这里主要讲Pull解析和SAX解析.这篇文章主要是讲Pull解析. 一.Pull解析参考代码 先上代码: private vo ...

  3. python每天定时发送短信脚本

    最近业务上需要每天解析txt文本或者excel文件,读取内容发送短信,发送的时间段可控,用python实现 安装pip依赖 pip install -r requirement.txt xlrd Py ...

  4. c++入门笔记

    对于有java基础的人来说,学习c++并不难,毕竟c++是java的前身. 何况还熟练掌握了java呢,哈哈. 安装gcc环境,照着菜鸟教程来. 开发工具ide使用vs,eclipse虽然用习惯了,这 ...

  5. 洛谷——P1907 设计道路

    P1907 设计道路 题目描述 Caesar远征高卢回来后,对你大加赞赏,他亲自来到Genoa视察. Genoa在你的建设下变得无比繁荣,由于财政收入的增加,你为城市修建了交通系统.古罗马的交通系统由 ...

  6. 深入理解正则表达式-----应用于检测csrf的正则表达式

    如何写检测和防御csrf的规则?我们可以利用正则表达式进行匹配.对POST包进行正则匹配,这里只是提供了一个思路. pcre:"/POST \/(?P<uri>.*?) HTTP ...

  7. 【BZOJ 2711】 2711: [Violet 2]After 17 (0-1 背包)

    2711: [Violet 2]After 17 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 224  Solved: 153 Description ...

  8. 51nod1423 最大二"货" 单调栈

    枚举每个点作为次大值,用单调栈处理出左边 / 右边第一个比它大的数,直接回答 复杂度$O(n)$ #include <cstdio> #include <cstring> #i ...

  9. luoguP4320 道路相遇 圆方树

    标题已经告诉你怎么做了..... 两点间的圆点个数即为所求 建出圆方树后打个树剖求$lca$就行..... 复杂度$O(n + q \log n)$ #include <cstdio> # ...

  10. AtCoder Beginner Contest 022 A.Best Body 水题

    Best Body Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://abc022.contest.atcoder.jp/tasks/abc02 ...