自定义View基础及常用示例(二)

来源:互联网 发布:linux arch 编辑:程序博客网 时间:2024/06/11 13:11

自定义View基础及常用示例(二)

  1. View和ViewGroup的事件分发
  2. 实例

View和ViewGroup组成的树形结构中,触摸事件通过特定的分发方式从顶层View向底层View传递,如果到底层都没有处理则会原路返回至根节点直到某个节点处理或拦截。

3. View和ViewGroup的触摸事件分发

Android触摸事件的分发,实际是先分发ACTION_DOWN事件,得知某个View处理了这个事件以后,其它事件如ACTION_MOVE和ACTION_UP都会通过分发直接传递到此层。

  1. View中的事件通过dispatchTouchEvent分发到onTouchEvent中,如果在onTouchEvent 中返回的是true表示要在这个View中消费,返回false表示在不消费,将事件回传到上层控件。

  2. ViewGroup覆盖了View中dispatchTouchEvent,因为ViewGroup中会有0个或多个View,分发的过程和View也有不同。有时ViewGroup需要消费触摸事件,所以在ViewGroup中增加了onInterceptTouchEvent()拦截的回调,默认情况下会返回false,表示不拦截事件,如果返回true则表示拦截,这时dispatchTouchEvent会将触摸事件分发至onTouchEvent中,往后的处理和View是一致的。ViewGroup分发时先判断是否拦截处理,如果没有拦截则会判断是否包含子View,当没有包含子View的时候则会使用View的dispatchTouchEvent进行分发,如果有一个或多个View的时候则会判断哪一个View在触摸位置,然后将这个事件传递给这个View的dispatchTouchEvent进行分发。

这里写图片描述

图来自 (图解Android 事件分发机制)

3.1 View 中只会有分发和处理的方法

(dispatchTouchEvent,OnTouchEvent)

dispatchTouchEvent 分发

实际上是传递Action.Down事件至目标视图节点

// Pass the touch screen motion event down to the target view, or this view if it is the target.public boolean dispatchTouchEvent(MotionEvent event)

一般不覆盖这个方法,因为这里已经处理了触摸事件的分发,如果覆盖后返回true则表示在这个方法里处理了触摸事件,上层无需再处理了,所以到这里就结束了,如果返回false表示在这里不处理,需要上层处理,触摸事件传递给上层。特别的:在ViewGroup中的dispatchTouchEvent() 如果不覆盖或使用super.dispatchTouchEvent,则表示继续传递触摸事件至子视图.

onTouchEvent

这里就是处理所有的触摸事件的回调方法,可以(返回true)消费也可以(返回false)不消费返回上层
这个方法会被实际操作或者performClick()(模拟点击)操作所触发,会执行以下操作
1. 响应点击,发出点击音
2. 触发 OnClickListener() 回调

// Implement this method to handle touch screen motion events.// True if the event was handled, false otherwise.public boolean onTouchEvent(MotionEvent event) 

OnTouchListener 监听

另外需要注意的是View 中 OnTouchListener
这个回调返回的值会影响后面onTouchEvent是否被执行,因为这个监听是在View 的 dispatchTouchEvent()中设置的,如果OnTouchListener不为空同时回调 onTouch() 时返回true 表示需要继续消费表现为继续分发, false表示不再消费,表现为停止分发

   /**     * Interface definition for a callback to be invoked when a touch event is     * dispatched to this view. The callback will be invoked before the touch     * event is given to the view.     */   public interface OnTouchListener {        /**         * Called when a touch event is dispatched to a view. This allows listeners to         * get a chance to respond before the target view.         *         * @param v The view the touch event has been dispatched to.         * @param event The MotionEvent object containing full information about         *        the event.         * @return True if the listener has consumed the event, false otherwise.         */        boolean onTouch(View v, MotionEvent event);    }

3.1 ViewGroup中会有分发、拦截、和处理的方法

ViewGroup对dispatchTouchEvent做了覆盖,处理了对子View的触摸事件的分发,如果自己没有拦截就向子View分发触摸事件

onInterceptTouchEvent

默认情况下返回的是false,不做拦截操作

boolean onInterceptTouchEvent (MotionEvent ev)

onInterceptTouchEvent added in API level 1
Implement this method to intercept all touch screen motion events.
This allows you to watch events as they are dispatched to your
children, and take ownership of the current gesture at any point.

Using this function takes some care, as it has a fairly complicated
interaction with View.onTouchEvent(MotionEvent), and using it requires
implementing that method as well as this one in the correct way.
Events will be received in the following order:

  1. You will receive the down event here.
  2. The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this
    means you should implement onTouchEvent() to return true, so you will
    continue to see the rest of the gesture (instead of looking for a
    parent view to handle it). Also, by returning true from
    onTouchEvent(), you will not receive any following events in
    onInterceptTouchEvent() and all touch processing must happen in
    onTouchEvent() like normal.
  3. For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here
    and then to the target’s onTouchEvent().
  4. If you return true from here, you will not receive any following events: the target view will receive the same event but with the
    action ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.

3.3 触摸事件的回传:

当触摸事件传递到底层View时,因为View中不能包含View的,所以触摸事件传递到的这个View必然是最底层的View了,相当于事件传递View树的叶子,当叶子的onTouchEvent返回false时,其dispatchTouchEvent()也会返回false,这样上层的ViewGroup的dispatchTouchEvent()会将触摸事件分发到ViewGroup自己的onTouchEvent中,同理,在这里如果返回true表示要消费,false则会再次回传至更上层的ViewGroup中。

http://www.jianshu.com/p/e99b5e8bd67b
图来自 (图解Android 事件分发机制)

触摸事件的分发机制就是在dispatchTouchEvent()方法中分发至onTouchEvent()的,当onTouchEvent()消费时(返回true),在dispatchTouchEvent()中判断在此层消费了,则自身返回true,上层的dispatchToutchEvent()得知触摸事件需要被消费(dispatchTransformedTouchEvent 中会调用 子View的 dispatchToutchEvent)以后又递归的向上层通知需要消费,经过消费ACTION_DOWN以后得知了消费的View,以后的ACTOIN_MOVE和ACTION_UP会直接从上之下分发到此View中,而不用传递到最底层再回传值View。

5. 实例

原创粉丝点击