view 事件体系

来源:互联网 发布:淘宝的丰胸精油 编辑:程序博客网 时间:2024/06/05 13:42

一、view基础

1、view的继承体系

View是Android中所有控件的基类,ViewGroup内部包含了许多个控件,即一组View。在Android的设计中,ViewGroup也继承了View,这就意味着View本身就可以是单个控件也可以是由多个控件组成的一组控件,通过这种关系就形成了View树的结构

我们给出一个简略图,可以直观的看到整个体系中常用类的继承结构
这里写图片描述

2.View的位置关系

view有3中坐标系:屏幕坐标系、视图坐标系、布局坐标系

屏幕坐标系:

以屏幕左上方为(0,0)的坐标体系,X/Y轴的最大值即为物理屏幕分辨率的宽和高;
触摸消息中MotionEvent.getRawX/getRawY取到的就是屏幕坐标值;

视图坐标系:

视图坐标是完全由自身view的宽高决定的坐标体系,理论上他是没有边界的,不受物理屏幕大小限制;
触摸消息中MotionEvent.getX/getY取到的就是视图坐标值;

布局坐标系:

子视图相对于父视图而言的相对屏幕坐标,以父视图的左上角为(0,0),而不关心父视图到底位于屏幕何处。
子视图View的位置主要由它的四个顶点来决定,分别对应于View的四个属性top、left、right,bottom,其中top是左上角纵坐标,left是左上角横坐标,right是右下角横坐标,bottom是有下角纵坐标。需要注意的是,这些坐标都是相对于View的父容器来说的,因此它是一种
相对坐标
这里写图片描述

图解各种系数获取方法

这里写图片描述

translationX,translationY

translationX,translationY是左上角相对父容器的偏移量

二、view触摸事件

MotionEvent

在手指接触屏幕后所产生的一系列事件中,典型的事件类型有如下几种:

  • ACTION_DOWN一手指刚接触屏幕
  • ACTION_MOVE一—手指在屏幕上移动
  • ACTION_UP——手机从屏幕上松开的一瞬间

TouchSlop

TouchSlop是系统所能识别出的被认为是滑动的最小距离,是一个常量,不同的设备下可能不同。可以用来过滤用户是否滑动。

ViewConfiguration.get(getContext()).getScaledTouchSlop() 

View 事件分发机制

触摸事件的分发,其实就是对MotionEvent事件的分发过程,一个MotionEvent产生后系统需要把这个事件传递给一个具体的View。

一、三个重要的方法dispatchTouchEvent,onInterceptTouchEvent和onTouchEvent;

1、dispatchTouchEvent:

用来进行事件的分发

2、onInterceptTouchEvent:

判断本view是否拦截触摸事件,返回true表示拦截,触摸事件不再下内部view传递,直接调用本view的onTouchEvent来处理触摸事件。反之继续向下层view传递。

3、onTouchEvent:

触摸事件实际的处理类,用来处理具体的触摸事件(up,down,move),如果返回true表示该事件被消耗,不在向上层传递该事件。反之上层view会调用onTouchEvent来处理该事件

二、简述一下分发机制:

当一个触摸事件产生后,它的传递过程遵循如下顺序:Activity>Window-View

现在有view1–>view2—>view3 3个view嵌套view1最外层,view3最底层

1、view1获取触摸事件,然后向下层传递,

2、如果中途的view1或者view2没有调用onInterceptTouchEvent进行拦截(返回false),就一直到最下层view3,最后因为view3没有下层view就会调用view3的onTouchEvent方法处理触摸事件,返回true表示已经处理,该事件将被view3消耗。如果false表示不处理,事件将继续回反给view2的onTouchEvent处理,以此类推。

3、如果view1,view2的onInterceptTouchEvent拦截(返回true),会立即调用view1或者view2 的onTouchEvent处理,不会向下传递,处理方式也和正常一样。

借用网上找到的伪代码表示:

 @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        boolean consume = false;        if(onInterceptTouchEvent(ev)){            consume = onTouchEvent(ev);        }else {            consume = child.dispatchTouchEvent(ev);        }        return consume;    }

以下内容来自互联网

关于事件传递的机制,这里给出一些结论,根据这些结论可以更好地理解整个传递机制,如下所示。

  • (1)同一个事件序列是指从手指接触屏幕的那一刻起,到手指离开屏慕的那一刻结束,在这个过程中所产生的一系列事件,这个事件序列以down事件开始,中间含有数量不定的move事件,最后以up结束

  • (2)正常情况下,一个事件序列只能被一个Visw拦截且消耗。这一条的原因可以参考(3),因为一旦一个元素拦截了某此事件,那么同一个事件序列内的所有事件都会直接交给它处理,因此同一个事件序列中的事件不能分别由两个View同时处理,但是通过特殊手段可以做到,比如一个Vew将本该自己处理的事件通过onTouchEvent强行传递给其他View处理。

  • (3)某个View一旦决定拦截,那么这一个事件序列都只能由它来处理(如果事件序列能够传递给它的话),并且它的onInterceprTouchEvent不会再被调用。这条也很好理解,就是说当一个View决定拦截一个事件后,那么系统会把同一个事件序列内的其他方法都直接交给它来处理,因此就不用再调用这个View的onInterceptTouchEvent去询问它是否要拦截了。

  • (4)某个View一旦开始处理事件,如果它不消耗ACTON_DOWN事件(onTouchEvent返回了false),那么同一事件序列中的其他事件都不会再交给它来处理,并且事件将重新交由它的父元素去处理,即父元素的onTouchEvent会被调用。意思就是事件一旦交给一个View处理,那么它就必须消耗掉,否则同一事件序列中剩下的事件就不再交给它来处理了,这就好比上级交给程序员一件事,如果这件事没有处理好,短期内上级就不敢再把事情交给这个程序员做了,二者是类似的道理。

  • (5)如果View不消耗除ACTION_DOWN以外的其他事件,那么这个点击事件会消失,此时父元素的onTouchEvent并不会被调用,并且当前View可以持续收到后续的事件,最终这些消失的点击事件会传递给Activity处理。

  • (6)ViewGroup默认不拦截任何事件。Android源码中ViewGroup的onInterceptTouchEvent方法默认返回false

  • (7)View没有onInterceptTouchEvent方法,一旦有点击事件传递给它,那么它的onTouchEvent方法就会被调用。

  • (8)view的onTouchEvent默认都会消耗事件(返回true),除非它是不可点击的(clickable和longClickable同时为false),View的longClickable属性默认都为false,clickable属性要分情况,比如Button的clickable属性默认为true,而TextView 的clickable属性默认为false

  • (9)view 的enable.属性不影响onTouchEvent的默认返回值。哪怕一个View是disable状态的,只要它的clickable或者longclickable有一个为true,那么它的onTouchEvent就返会true。

  • (10)onclick会发生的前提实际当前的View是可点击的,并且他收到了down和up的事件

  • (11)事件传递过程是由外到内的,理解就是事件总是先传递给父元素,然后再由父元素分发给子View,通过requestDisallowInterptTouchEvent方法可以再子元素中干预元素的事件分发过程,但是ACTION_DOWN除外

1 0
原创粉丝点击