安卓触摸事件的分发,处理和消费,以及实现图片的拖动效果

Touch事件分发中只有两个主角:ViewGroup和View。Activity的Touch事件事实上是调用它内部的ViewGroup的Touch事件,可以直接当成ViewGroup处理。

View在ViewGroup内,ViewGroup也可以在其他ViewGroup内,这时候把内部的ViewGroup当成View来分析。

ViewGroup的相关事件有三个:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。View的相关事件只有两个:dispatchTouchEvent、onTouchEvent。

而dispatchTouchEvent是用来分发触摸事件的,onTouchEvent是用来处理触摸事件的()

第一步、触摸事件的产生:

触摸事件由用户触摸屏幕,系统会生成一个MotionEvent触摸事件对象,里面封装了此次动作的所用信息,如时间,位置坐标等。

然后系统会将当前这个触摸事件交给当前的Activity来处理。

第二步、触摸事件的分发与处理:

1、系统将触摸事件交给Activity处理后,会调用Activity的dispatchTouchEvent方法进行事件的分发,Activity首先会找到活动对应的布局中的

父ViewGroup,将触摸事件交给他处理。

2、然后这个ViewGroup又会调用自身的dispatchTouchEvent方法对事件进行分发:

这里又分为两种情况:

第一种是ViewGroup分发事件找到了对应的子View进行处理。

交给它的子孩子View来处理,子孩子View得到事件后,也会调用自身的dispatchTouchEvent方法,但是View的分发则是调用View自身的onTouchEvent或者View设置的

OnTouchListener的onTouch方法对事件进行处理(这里值得一提的是,onTouch方法的优先级是比onTouchEvent方法的优先级高,即先执行onTouch方法)。

在onTouchEvent和onTouch方法中,都需要返回一个布尔类型的值,如果返回true,则说明触摸事件已经消费,不在往下传递,有拦触摸截掉事件的意义,其他子

View就不能响应到这个触摸事件,如果返回false,则说明触摸事件没有被消费,需要传递给其他子View处理。如果所有的子View都不消费这个触摸事件

,最后这个触摸事件就会交由Activity的onTouchEvent处理。

一个完整触摸事件由down、move、up组成。

这里值得我注意的是:Activity分发事件是根据该View是否消费了动作为Down的触摸事件,如果没有消费,则不会向它分发动作为UP和MOVE的触摸事件。

第二种是ViewGroup分发事件没找到对应的子View进行处理。

这时事件就由ViewGroup自己处理,它会调用自身的onTouchEvent返回false,说明事件没有找到消费者,触摸事件没有被消费,move,up 动作不需要再往下分发了,

直接调用当前Activity的onTouchEvent(ev)方法处理。

只有View消费了动作为Down的触摸事件,这个View才能响应其他两个动作的触摸事件。

说完安卓事件的分发,接下来我们就来说说图片拖动效果的实现。

第一步、为ImageView设置一个OnTouchListener,并实现其onTouch方法

第二步、拖动逻辑的实现:

1、手指按到imageView上会有一个初始位置(startX,startY)

2、手指在屏幕上移动,移动到一个新的位置(nowX,nowY)

3、计算手指在屏幕的偏移量

dx=nowX-startX

dy=nowY-startY

4、重新计算图片的位置,并控制范围,使图片不会超出边框

 int left=miv_show.getLeft()+dx;
 int top=miv_show.getTop()+dy;
 int right=miv_show.getRight()+dx;
 int buttom=miv_show.getBottom()+dy;
            if(left<=0){
                        right+=-left;
                        left=0;
                    }
                    if(top<=0){
                        buttom+=-top;
                        top=0;
                    }
                    if(right>=mRight){
                        left+=-(right-mRight);
                        right=mRight;
                    }
                    if(buttom>=mButtom){
                        top+=-(buttom-mButtom);
                        buttom=mButtom;
                    }
 

5、通过调用imageView.layout(left,top,right,bottom)立即更新imageView的位置

(left指的是图片左上角的x坐标,top指的是图片左上角的y坐标,right指的是右下角的x坐标,bottom知道是图片右下角的y坐标)

6、重新初始化手指的开始位置(startX=nowX,startY=nowY)

7、当手指离开图片的时候记录当前图片的位置,在下次imageView加载完成后回显。

这里问题就来了,imageView什么时候会加载完成呢?当活动创建调用onCreate方法的时候

imageView是还没有加载完成的,如果在onCreate方法中调用imageView.layout方法是不起作用的

,故我们要设置一个监听,当图片加载完成后回调该监听的方法,在这个方法里面调用layout回显图片的位置,

代码如下:

miv_show.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                System.out.println("view加载完成");
                int lastLeft=sp.getInt("lastLeft", 0);
                int lastTop=sp.getInt("lastTop", 0);
                int lastRight=sp.getInt("lastRight", 0);
                int lastButtom=sp.getInt("lastButtom", 0);
                if(!(lastLeft==0&&lastTop==0&&lastRight==0&&lastButtom==0)){
                    //说明保存了位置
                    miv_show.layout(lastLeft, lastTop, lastRight, lastButtom);
                }
            }
        });

代码实现如下:

miv_show.setOnTouchListener(new OnTouchListener() {
            private int startX;
            private int startY;
            @Override
            public boolean onTouch(View v, MotionEvent event){
                int mRight=rl.getRight();
                int mButtom=rl.getBottom();
                switch(event.getAction()){
                case MotionEvent.ACTION_DOWN:
                    startX=(int) event.getRawX();
                    startY=(int) event.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    int nowX=(int) event.getRawX();
                    int nowY=(int) event.getRawY();

                    int dx=nowX-startX;
                    int dy=nowY-startY;

                    int left=miv_show.getLeft()+dx;
                    int top=miv_show.getTop()+dy;
                    int right=miv_show.getRight()+dx;
                    int buttom=miv_show.getBottom()+dy;
                    if(left<=0){
                        right+=-left;
                        left=0;
                    }
                    if(top<=0){
                        buttom+=-top;
                        top=0;
                    }
                    if(right>=mRight){
                        left+=-(right-mRight);
                        right=mRight;
                    }
                    if(buttom>=mButtom){
                        top+=-(buttom-mButtom);
                        buttom=mButtom;
                    }
                    miv_show.layout(left,top, right, buttom);

                    startX=nowX;
                    startY=nowY;

                    break;

                case MotionEvent.ACTION_UP:
                    int lastLeft=miv_show.getLeft();
                    int lastTop=miv_show.getTop();
                    int lastRight=miv_show.getRight();
                    int lastButtom=miv_show.getBottom();
                    Editor editor=sp.edit();
                    editor.putInt("lastLeft", lastLeft);
                    editor.putInt("lastTop", lastTop);
                    editor.putInt("lastRight", lastRight);
                    editor.putInt("lastButtom", lastButtom);
                    editor.commit();
                    break;
                }

                //返回true代表事件已经消费了,不需要再往下传递
                //代表所有触摸事件都在这里被消费了,不再往下传递
                return true;
            }
        });
时间: 2024-10-06 10:42:25

安卓触摸事件的分发,处理和消费,以及实现图片的拖动效果的相关文章

测试安卓触摸事件的分发机制

概要: Activity |dispatchTouchEvent  ========================> ^onTouchEvent -- PhotoWindow.FragmentLayout ViewGroup |dispatchTouchEvent  = onInterceptTouchEvent > |onTouchEvent View |dispatchTouchEvent  ========================> |onTouchEvent 其中, 角

Android自定义控件系列 十:利用添加自定义布局来搞定触摸事件的分发,解决组合界面中特定控件响应特定方向的事件

这个例子是比较有用的,基本上可以说,写完这一次,以后很多情况下,直接拿过来addView一下,然后再addInterceptorView一下,就可以轻轻松松的达到组合界面中特定控件来响应特定方向的触摸事件了. 请尊重原创劳动成果,转载请注明出处:http://blog.csdn.net/cyp331203/article/details/45198549,非允许请勿用于商业或盈利用途,违者必究. 在写Android应用的过程之中,经常会遇到这样的情况:界面包含了多个控件,我们希望触摸在界面上的不

一个demo让你彻底理解Android中触摸事件的分发

注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOWN.ACTION_MOVE.ACTION_UP.当用户手指接触屏幕时,便产生一个动作为ACTION_DOWN的触摸事件,此时若用户的手指立即离开屏幕,会产生一个动作为ACTION_UP的触摸事件:若用户手指接触屏幕后继续滑动,当滑动距离超过了系统中预定义的距离常数,则产生一个动作为ACTION_MO

深入了解触摸事件的分发

1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOWN.ACTION_MOVE.ACTION_UP.当用户手指接触屏幕时,便产生一个动作为ACTION_DOWN的触摸事件,此时若用户的手指立即离开屏幕,会产生一个动作为ACTION_UP的触摸事件:若用户手指接触屏幕后继续滑动,当滑动距离超过了系统中预定义的距离常数,则产生一个动作为ACTION_MOVE的触摸事件,系统中预定义的用来判断用户手指在屏幕上的滑动是否是一个ACTION_MOVE动作的这个距离常量叫

从ScrollView嵌套EditText的滑动事件冲突分析触摸事件的分发机制以及TextView的简要实现和冲突的解决办法

本篇文章假设读者没有任何的触摸事件基础知识,所以我们会从最基本的触摸事件分发处说起. ScrollView为什么会出现嵌套EditText出现滑动事件冲突呢?相信你会有这种疑问,我们来看这么一种情况: 有一个固定高度的EditText,假设它只能显示3行文本,但是,我们在其中输入的文本多余三行时,那么这时就需要可以在EditText内部进行小幅滚动了.那么将这个EditText放入了ScrollView当中, 并且ScrollView内容过多以致ScrollView也可以滑动,这时候就会出现Ed

Android触摸事件分发

Android的触摸分发机制和如何实现拦截 Android的触摸分发机制和如何实现拦截 前言 触摸事件的分发 情景分析 总结 前言 在自定义ViewGroup中,有时候需要实现触摸事件拦截,比如ListView下拉刷新就是典型的触摸事件拦截的例子.触摸事件拦截就是在触摸事件被parent view拦截,而不会分发给其child,即使触摸发生在该child身上.被拦截的事件会转到parent view的onTouchEvent方法中进行处理.但是这个交互过程还是挺复杂的,有多种情况,今天我们就来分

android源码解析(三十)--&gt;触摸事件分发流程

前面一篇文章中我们分析了App返回按键的分发流程,从Native层到ViewRootImpl层到DocorView层到Activity层,以及在Activity中的dispatchKeyEvent方法中分发事件,最终调用了Activity的finish方法,即销毁Activity,所以一般情况下假如我们不重写Activity的onBackPress方法或者是onKeyDown方法,当我们按下并抬起返回按键的时候默认都是销毁当前Activity.而本文中我们主要介绍触摸事件的分发流程,从Nativ

IOS 触摸事件分发机制详解

欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:MelonTeam 前言 很多时候大家都不关心IOS触摸事件的分发机制的实现原理,当遇到以下几种情形的时候你很可能抓破头皮都找不到解决方案: 某个点击消息由父视图来处理,子视图怎么把消息传递给父视图 这个按钮不灵敏,怎么扩大点击响应区域 怎么在一个页面处理手绘.表情拖动放缩.文本编辑三种消息 阅读本文,你会明白两个问题:IOS如何找到响应者.响应者是如何做出响应,明白这两个问题你就能解决类似上述的疑难杂症.通过控制Hit-test v

Android ViewGroup触摸事件拦截详解

前言 在自定义ViewGroup中,有时候需要实现触摸事件拦截,比如ListView下拉刷新就是典型的触摸事件拦截的例子.触摸事件拦截就是在触摸事件被parent view拦截,而不会分发给其child,即使触摸发生在该child身上.被拦截的事件会转到parent view的onTouchEvent方法中进行处理.但是这个交互过程还是挺复杂的,有多种情况,今天我们就来分析一下吧.这篇分析文章已经放了一段时间了,如果有任何问题请高人指出. 触摸事件的分发 简单来说触摸事件的分发会经过这么几个顺序