Android触摸事件分发机制详解

本文详细分析了Android中的触摸事件分发机制,包括dispatchTouchEvent、onInterceptTouchEvent、requestDisallowInterceptTouchEvent、onTouch、onTouchEvent和onClick等方法的作用和执行顺序。还探讨了事件的传递顺序、ACTION_DOWN的重要性以及onInterceptTouchEvent的拦截功能。通过对事件流的图解和日志分析,阐述了事件如何在Activity、ViewGroup和View之间流转和被消费,以及ACTION_CANCEL事件的出现场景。
摘要由CSDN通过智能技术生成

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

转载请注明出处:https://blog.csdn.net/binbinqq86/article/details/82315399

文章目录


#前言

触摸事件分发机制一直以来都是Android中比较重要的一大块,自定义view,各种复杂的自定义手势交互都与触摸事件分发机制关系密切,想要做好这些,就要对触摸事件了解透彻,并且需要不断的去实践来加深印象,否则在自己去实现的时候就会茫然不知所措,同时这个知识点也是面试必问的经典题目,所以说掌握它是必须的,今天就来详细分析一下整个触摸事件的分发流程和相关知识。(本文理论知识较多,比较枯燥,需要极大耐心观看~)

#触摸事件相关方法
触摸事件大致涉及以下几个方法:
##1、dispatchTouchEvent

/**
     * Pass the touch screen motion event down to the target view, or this
     * view if it is the target.
     *
     * @param event The motion event to be dispatched.
     * @return True if the event was handled by the view, false otherwise.
     */
    public boolean dispatchTouchEvent(MotionEvent event) {
		//......
}

从源码里的注解可以看到,该方法主要是用来进行事件分发和传递的,当返回true的时候代表自己去处理,把事件传递给自己,否则就传递给其他的view。该方法也是触摸事件第一个执行的方法,后续的几个是否执行都取决于它。

##2、onInterceptTouchEvent

这个方法主要是viewGroup特有的,用来做触摸事件拦截的,默认返回false:

/**
     * 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.
     *
     * <p>Using this function takes some care, as it has a fairly complicated
     * interaction with {@link View#onTouchEvent(MotionEvent)
     * 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:
     *
     * <ol>
     * <li> You will receive the down event here.
     * <li> 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.
     * <li> 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().
     * <li> 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 {@link MotionEvent#ACTION_CANCEL}, and all further
     * events will be delivered to your onTouchEvent() method and no longer
     * appear here.
     * </ol>
     *
     * @param ev The motion event being dispatched down the hierarchy.
     * @return Return true to steal motion events from the children and have
     * them dispatched to this ViewGroup through onTouchEvent().
     * The current target will receive an ACTION_CANCEL event, and no further
     * messages will be delivered here.
     */
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
                && ev.getAction() == MotionEvent.ACTION_DOWN
                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
                && isOnScrollbarThumb(ev.getX(), ev.getY())) {
            return true;
        }
        return false;
    }

可以看到注释是很长的,也是很详细的,我这里大致翻译一下里面几个重要的点:

  • 主要是用来做事件分发过程中的拦截的,相当于一个拦截器
  • 如果返回false或者super,则事件继续传递,事件所经过的每一层的viewGroup都会去调用该方法来询问是否拦截
  • 如果返回true,则代表拦截该事件,停止传递给子view,会走自己的onTouchEvent事件
  • 不像onTouchEvent是否拦截取决于down事件,该方法每个事件都可以去做拦截
  • 事件一经拦截,后续move、up事件都直接交给onTouchEvent,不会重新去询问是否拦截(即不再调用onInterceptTouchEvent)
  • 事件被拦截后,子view会接收到一个cancel事件,来恢复之前的状态,结束当前事件流

##3、requestDisallowInterceptTouchEvent

/**
     * Called when a child does not want this parent and its ancestors to
     * intercept touch events with
     * {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}.
     *
     * <p>This parent should pass this call onto its parents. This parent must obey
     * this request for the duration of the touch (that is, only clear the flag
     * after this parent has received an up or a cancel.</p>
     * 
     * @param disallowIntercept True if the child does not want the parent to
     *            intercept touch events.
     */
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept);

这个方法也是用来做事件拦截的,也是viewGroup专有的方法,不过一般是在子view中来调用的,根据注释:当一个子view不希望它的父view来通过onInterceptTouchEvent方法拦截事件的时候,调用该方法即可实现事件的传递和接管,并且在整个事件流中,父view以及再往上的父view都要遵守该规则。

##4、onTouch

/**
         * 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);

这个也是触摸事件,方便给开发者调用的。根据注释:当一个触摸事件被分发到一个view的时候,就会调用该方法,它是在事件传递到onTouchEvent之前被调用的。

##5、onTouchEvent

/**
     * Implement this method to handle touch screen motion events.
     * <p>
     * If this 
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值