码迷,mamicode.com
首页 > 其他好文 > 详细

手势识别 GestureDetector ScaleGestureDetector

时间:2016-06-30 17:55:26      阅读:423      评论:0      收藏:0      [点我收藏+]

标签:


识别器GestureDetector基本介绍
当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等。一般情况下,我们可以通过View或Activity的onTouchEvent,或实现OnTouchListener接口后通过onTouch方法,处理一些touch事件,但是这个方法太过简单,如果需要处理一些复杂的手势,用这个接口就会很麻烦(因为我们要自己根据用户触摸的轨迹去判断是什么手势)。为此,Android 给我们提供了GestureDetector(Gesture:手势,Detector:识别),通过这个类我们可以识别很多的手势,主要是通过他的onTouchEvent方法完成不同手势的识别。
虽然他能识别手势,但是不同的手势要怎么处理,还是给程序员自己要实现的。

注意:
默认情况下,GestureDetector是监听不到MotionEvent事件的,也即GestureDetector的onTouchEvent方法是不会被调用的,若要被调用,必须满足两个条件
  • ①在View的onTouchEvent()方法中,须将MotionEvent事件手动【传】给GestureDetector
  • ②若View设置了.setOnTouchListener()监听器,则其onTouch()的返回值还须是【false】,或者在onTouch()中将MotionEvent事件手动【传】给GestureDetector
只有这样,GestureDetector 注册的OnGestureListener(单击)或OnDoubleTapListener(双击)才能获得完整的MotionEvent事件,进而根据该对象封装的的信息,做出合适的反馈。

识别器ScaleGestureDetector基本介绍
ScaleGestureDetector是Android2.2 新增的类,其能使 Views 通过接收到的 MotionEvents ,检测包括多点触摸在内的手势变化信息,当检测到此类信息后,监听器OnScaleGestureListener 便会调用相应的回调方法通知用户,其最简单常用的应用场景就是使用双指缩放图片。
注意,ScaleGestureDetector是直接继承自object的,并非GestureDetector的子类。

监听器OnScaleGestureListener回调方法有onScale(ScaleGestureDetector) 、onScaleBegin、onScaleEnd
ScaleGestureDetector中定义的公共方法:
  • public float getCurrentSpan () 返回手势过程中,组成该手势的两个触点的当前距离。
  • public long getEventTime () 返回事件被捕捉时的时间。
  • public float getFocusX () 返回当前手势焦点的 X 坐标。 如果手势正在进行中,焦点位于组成手势的两个触点之间。 如果手势正在结束,焦点为仍留在屏幕上的触点的位置。若 isInProgress() 返回 false,该方法的返回值未定义。
  • public float getFocusY ()  返回当前手势焦点的 Y 坐标。
  • public float getPreviousSpan () 返回手势过程中,组成该手势的两个触点的前一次距离。
  • public float getScaleFactor () 返回从前一个伸缩事件至当前伸缩事件的伸缩比率。该值定义为  getCurrentSpan() / getPreviousSpan()。
  • public long getTimeDelta () 返回前一次接收到的伸缩事件距当前伸缩事件的时间差,以毫秒为单位。
  • public boolean isInProgress () 如果手势处于进行过程中,返回 true。否则返回 false

手势监听器SimpleOnGestureListeren
我们只需要继承SimpleOnGestureListener重载自己需要监听的手势即可
public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {}

OnGestureListener的监听事件
  • 按下(onDown): 刚刚手指接触到触摸屏的那一刹那,就是触的那一下
  • 抛掷(onFling): 手指在触摸屏上迅速移动,并松开的动作,onDown---onScroll---onScroll---…onFling
  • 长按(onLongPress): 手指按在持续一段时间,并且没有松开
  • 滚动(onScroll): 手指在触摸屏上滑动,onDown---onScroll---onScroll---…onScroll
  • 按住(onShowPress): 手指按在触摸屏上,在按下起效,在长按前失效,onDown->onShowPress->onLongPress
  • 抬起(onSingleTapUp):手指离开触摸屏的那一刹那
技术分享

OnDoubleTapListener的监听事件
  • onDoubleTap,双击的【第二下】down时触发(只执行一次)
  • onDoubleTapEvent,双击的【第二下】down和up都会触发(执行次数不确定)
  • onSingleTapConfirmed单击确认,即很快的按下并抬起,但并不连续点击第二下
技术分享

注意:
  • onSingleTapConfirmed(单击)和onSingleTapUp都是在down后既没有滑动onScroll,又没有长按onLongPress时, up 时触发的
  • 非常快的点击一下:onDown->onSingleTapUp->onSingleTapConfirmed
  • 稍微慢点的点击一下:onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed(最后一个不一定会触发)

演示代码-在Activity中使用
上面的图片是添加了GestureDetector和ScaleGestureDetector的ImageView,并且在【onTouchEvent】方法中将事件传递给手势识别器,且返回【true】
下面的图片是在上面图片基础上注册了【OnTouchListener】,若在其【onTouch】方法中返回【true】,则就会导致其注册的手势识别器全部失效!
我们为Activity自身注册了GestureDetector和ScaleGestureDetector,并且在其【onTouchEvent】方法中将事件传递给手势识别器,返回值使用默认逻辑值
public class MainActivity extends Activity {
    private GestureDetector mGestureDetector;//用于Activity自身的单击和双击事件手势识别器
    private ScaleGestureDetector mScaleGestureDetector;//用于Activity自身的缩放事件手势识别器
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyImageView myImageView = (MyImageView) findViewById(R.id.iv);
        myImageView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return true;//返回值要为false,或者直接在此onTouch()中将MotionEvent事件手动传给GestureDetector,才能使手势识别器生效
            }
        });
        //**************************************************************************************************************************
        mGestureDetector = new GestureDetector(thisnew SimpleOnGestureListener() {
            @Override
            //监测双击事件
            public boolean onDoubleTap(MotionEvent e) {
                Log.e("Activity-手势""onDoubleTap");
                return super.onDoubleTap(e);
            }
        });
        mScaleGestureDetector = new ScaleGestureDetector(thisnew SimpleOnScaleGestureListener() {
            @Override
            //监测缩放
            public boolean onScale(ScaleGestureDetector detector) {
                DecimalFormat df = new DecimalFormat("0.00");//格式化float
                Log.e("Activity-缩放""onScale," + df.format(detector.getScaleFactor()) + "-" + //缩放因子,两指靠拢时小于1
                        df.format(detector.getFocusX()) + "-" + df.format(detector.getFocusY()));//中心点坐标
                return super.onScale(detector);
            }
        });
    }
    //**************************************************************************************************************************
    @Override
    //重写屏幕触摸事件onTouchEvent,将触摸事件传给GestureDetector
    public boolean onTouchEvent(MotionEvent event) {
        try {
            //在onTouchEvent方法中可以完成所有GestureDetector的操作,因为他们都只需要一个MotionEvent的参数
            Log.e("Activity-多点触摸""onTouchEvent" + spacing(event));
        } catch (Exception e) {
        }
        mGestureDetector.onTouchEvent(event);
        mScaleGestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }
    /**
     * 返回两个点之间的距离
     */
    private float spacing(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);
    }
}

演示代码-在View中使用
public class MyImageView extends ImageView {
    private GestureDetector mGestureDetector;//单击和双击事件手势识别
    private ScaleGestureDetector mScaleGestureDetector;//缩放事件手势识别
    public MyImageView(Context context) {
        this(context, null);
    }
    public MyImageView(Context context, AttributeSet attr) {
        super(context, attr);
        mGestureDetector = new GestureDetector(context, new MyGestureListener());
        mScaleGestureDetector = new ScaleGestureDetector(context, new MyScaleGestureListener());
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetector.onTouchEvent(event);
        mScaleGestureDetector.onTouchEvent(event);
        //return super.onTouchEvent(event);//不管返回值是什么,都能接收down事件,都能触发onDown、onShowPress、onLongPress
        return true;//但只有返回true才能继续接收move,up等事件,也才能响应ScaleGestureDetector事件及GestureDetector中与move,up相关的事件
    }
    //**************************************************************************************************************************
    private class MyScaleGestureListener extends SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            Log.e("view-缩放""onScale," + detector.getScaleFactor());
            return super.onScale(detector);
        }
        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            Log.e("view-缩放""onScaleBegin");
            return super.onScaleBegin(detector);
        }
        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            Log.e("view-缩放""onScaleEnd");
        }
    }
    //**************************************************************************************************************************
    private class MyGestureListener extends SimpleOnGestureListener {
        @Override
        //双击的【第二下】Touch down时触发(只执行一次)
        public boolean onDoubleTap(MotionEvent e) {
            Log.e("view-手势""onDoubleTap");
            return super.onDoubleTap(e);
        }
        @Override
        //双击的【第二下】Touch down和up都会触发(执行次数不确定)。 
        public boolean onDoubleTapEvent(MotionEvent e) {
            Log.e("view-手势""onDoubleTapEvent");
            return super.onDoubleTapEvent(e);
        }
        @Override
        //Touch down时触发
        public boolean onDown(MotionEvent e) {
            Log.e("view-手势""onDown");
            return super.onDown(e);
        }
        @Override
        //onScroll一点距离后,【抛掷时】触发(若是轻轻的、慢慢的停止活动,而非抛掷,则很可能不触发)
        //参数为手指接触屏幕、离开屏幕一瞬间的动作事件,及手指水平、垂直方向移动的速度,像素/秒
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            Log.e("view-手势""onFling");
            if ((e2.getRawX() - e1.getRawX()) > 100) {
                Log.e("view-手势""onFling-从左到右滑");
                return true;
            }
            return super.onFling(e1, e2, velocityX, velocityY);
        }
        @Override
        //Touch了不移动一直Touch down时触发 
        public void onLongPress(MotionEvent e) {
            Log.e("view-手势""onLongPress");
            super.onLongPress(e);
        }
        @Override
        //Touch了滑动时触发,e1代表触摸时的事件,是不变的,e2代表滑动过程中的事件,是时刻变化的
        //distance是当前event2与上次回调时的event2之间的距离,代表上次回调之后到这次回调之前移动的距离
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            Log.e("view-手势""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.e("view-手势""onShowPress");
            super.onShowPress(e);
        }
        @Override
        //在touch down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touchup时触发。
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Log.e("view-手势""onSingleTapConfirmed");
            return super.onSingleTapConfirmed(e);
        }
        @Override
        //在touch down后又没有滑动(onScroll),又没有长按(onLongPress),然后Touchup时触发。
        public boolean onSingleTapUp(MotionEvent e) {
            Log.e("view-手势""onSingleTapUp");
            return super.onSingleTapUp(e);
        }
    }
}

布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#1234"
    android:orientation="vertical" >
    <com.bqt.test.MyImageView
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:background="#10ff"
        android:src="@drawable/ic_launcher" />
    <com.bqt.test.MyImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:background="#1f00"
        android:src="@drawable/ic_launcher" />
</LinearLayout>





手势识别 GestureDetector ScaleGestureDetector

标签:

原文地址:http://www.cnblogs.com/baiqiantao/p/5630506.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!