Android View事件传递机制

本文深入探讨了Android中View和ViewGroup的事件传递机制,包括dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent的作用及顺序。通过具体示例和代码演示了不同情况下事件如何被分发、拦截和处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

view事件传递机制,在很多面试中会问道,我曾经也被问道,却没有回答上来。

写这篇博客前参考了https://blog.csdn.net/zuguorui/article/details/76862816。在这里感谢该作者,写的很详细。

今天我在这里写了一个demo去理解这个view的事件传递机制。

首先这个view包括两种,viewGroup和普通view。viewGroup就是里面还可以包含子控件的那种,如LinearLayout,ViewPager;view是指不能包含子view的那种,如Button,TextView,ImageView 等。

viewGroup的view传递事件按顺序是:

dispatchTouchEvent(分发)
onInterceptTouchEvent(拦截)
onTouchEvent(触摸)

view的事件传递顺序是

dispatchTouchEvent(分发)
onTouchEvent(触摸)

两者结合的一般顺序是

如果子控件没有消费掉触摸事件

viewPager: dispatchTouchEvent
viewPager: onInterceptTouchEvent
myImageView: dispatchTouchEvent
myImageView: onTouchEvent
viewPager: onTouchEvent

如果子控件消费掉触摸事件,比如执行了onClick方法,执行完onClick后,就不会再执行父控件的onTouchEvent

viewPager: dispatchTouchEvent
viewPager: onInterceptTouchEvent
myImageView: dispatchTouchEvent
myImageView: onTouchEvent
myImageView: onclick

 

如果onInterceptTouchEvent 返回true,则父控件消费触摸事件

如果onInterceptTouchEvent 返回false,则子控件消费触摸事件

 

我们来写demo看看,这个机制到底是怎么实现的。我使用viewPage和image做的测试。

我自己测试发现一个有趣的事情,

1、onInterceptTouchEvent 不做任何修改,

return super.onInterceptTouchEvent(ev)

          a 子view的onTouchEvent 不做任何修改

     return super.onTouchEvent(event);

如果子view不消费onTouchEvent 事件,则一次滑动中,父控件不会多次调用onInterceptTouchEvent

09-13 16:55:21.427 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:55:21.428 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 16:55:21.429 6089-6089/ylj.com.vieweventapplication E/view_event_myImageView: dispatchTouchEvent
09-13 16:55:21.429 6089-6089/ylj.com.vieweventapplication E/view_event_myImageView: onTouchEvent
09-13 16:55:21.429 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:55:21.438 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:55:21.438 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:55:21.452 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:55:21.452 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:55:21.460 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:55:21.460 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:55:21.468 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:55:21.468 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:55:21.476 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:55:21.477 6089-6089/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent

b 如果子控件onTouchEvent 返回true,view group 则会多次调用onInterceptTouchEvent。

09-13 17:12:47.652 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.652 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 17:12:47.652 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: dispatchTouchEvent
09-13 17:12:47.652 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: onTouchEvent
09-13 17:12:47.727 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.727 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 17:12:47.727 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: dispatchTouchEvent
09-13 17:12:47.727 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: onTouchEvent
09-13 17:12:47.738 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.738 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 17:12:47.738 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: dispatchTouchEvent
09-13 17:12:47.738 7371-7371/ylj.com.vieweventapplication E/view_event_myImageView: onTouchEvent
09-13 17:12:47.760 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.760 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 17:12:47.776 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.776 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 17:12:47.777 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 17:12:47.777 7371-7371/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
2、onInterceptTouchEvent 返回true

输出如下,不会调用子view的方法

09-13 16:52:34.841 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:52:34.841 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onInterceptTouchEvent
09-13 16:52:34.842 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:52:34.848 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:52:34.848 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:52:34.864 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:52:34.864 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent
09-13 16:52:34.871 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: dispatchTouchEvent
09-13 16:52:34.871 4478-4478/ylj.com.vieweventapplication E/view_event_viewPager: onTouchEvent

3、onInterceptTouchEvent 返回false,子view的onTouchevent

return super.onTouchEvent(event);

这个时候,viewPager 可以滑动

3、onInterceptTouchEvent 返回false,子view的onTouchevent

return true;

这个时候,viewPager 就不能滑动了

测试源码如下,复写的viewPager 

package ylj.com.vieweventapplication;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

/**
 * Created by dfgx_yinlijuan on 2018/9/13.10:06
 */

public class MyViewPager extends ViewPager {
    String tag="viewPager";
    public MyViewPager(@NonNull Context context) {
        super(context);

    }

    public MyViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Tools.log(tag,"dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        Tools.log(tag,"onTouchEvent");
        return super.onTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Tools.log(tag,"onInterceptTouchEvent");
        return super.onInterceptTouchEvent(ev);
//        return false;
    }
}

复写的ImageView

package ylj.com.vieweventapplication;

import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

/**
 * Created by dfgx_yinlijuan on 2018/9/13.14:49
 */

public class MyImageView extends android.support.v7.widget.AppCompatImageView {
    String tag="myImageView";
    public MyImageView(Context context) {
        super(context);
    }

    public MyImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Tools.log(tag,"dispatchTouchEvent");
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Tools.log(tag,"onTouchEvent");
        return super.onTouchEvent(event);
//        return true;
    }

}

activity 调用

package ylj.com.vieweventapplication;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * view 事件传递机制demo
 */
public class ViewEventActivty extends AppCompatActivity {
    final String tag = "button";
    ViewPager viewPager;
    List<View> views=new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actvity_view_event);
        MyViewPager viewPager = (MyViewPager) findViewById(R.id.viewPager);


//        viewPager.setAdapter(new GuidePageAdapter());
        for (int i = 0; i < 3; i++) {
            MyImageView imageView = new MyImageView(this);
            if (i == 0) {
                imageView.setBackgroundColor(Color.RED);
            } else if (i == 1) {
                imageView.setBackgroundColor(Color.GREEN);
            } else if (i == 2) {
                imageView.setBackgroundColor(Color.BLUE);
            }
            imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            views.add(imageView);

        }

        GuideAdapter adapter = new GuideAdapter(views);
        viewPager.setAdapter(adapter);
    }

    class GuideAdapter extends PagerAdapter {
        List<View> mViews;

        GuideAdapter(List<View> views) {
            this.mViews = views;
        }

        @Override
        public int getCount() {
            return mViews.size();
        }

        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view==object;
        }

        @Override
        public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            ((ViewPager) container).removeView(mViews.get(position));
        }

        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            ((ViewPager)container).addView(mViews.get(position));
            return mViews.get(position);
        }
    }
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值