美文网首页Android自定义View
View的Touch事件分发

View的Touch事件分发

作者: 世道无情 | 来源:发表于2018-03-29 07:56 被阅读7次

1. 说明


这节课我们就来分析系View的Touch事件分发的顺序。

2. 分析

public class MainActivity extends AppCompatActivity {

    private TouchView touch_view;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        touch_view = (TouchView) findViewById(R.id.touch_view);

        touch_view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG" , "触摸onTouch() -> " + event.getAction()) ;
                return true;
            }
        });


        touch_view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG" , "点击onClick -> ") ;
            }
        });
    }
}
public class TouchView extends View {

    public TouchView(Context context) {
        super(context);
    }

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

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


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TAG" , "onTouchEvent -> " + event.getAction()) ;
        return super.onTouchEvent(event);
    }
}

现象一:onTouchListener、onTouch、onClick三个都有的情况下,并且onTouchListener返回false,表示自己不处理事件,直接把事件分发下去给子控件,所以3个方法都会执行;

03-25 08:18:36.589 3344-3344/com.jackchen.view_day010_2 E/TAG: 触摸onTouch() -> 0
03-25 08:18:36.589 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 0
03-25 08:18:36.672 3344-3344/com.jackchen.view_day010_2 E/TAG: 触摸onTouch() -> 2
03-25 08:18:36.672 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 2
03-25 08:18:36.851 3344-3344/com.jackchen.view_day010_2 E/TAG: 触摸onTouch() -> 1
03-25 08:18:36.851 3344-3344/com.jackchen.view_day010_2 E/TAG: onTouchEvent -> 1
03-25 08:18:36.852 3344-3344/com.jackchen.view_day010_2 E/TAG: 点击onClick -> 

由以上可知:0代表DOWN、2代表MOVE、1代表UP,执行顺序如下:
onTouchListener的DOMN -> onTouch的DOWN ->
onTouchListener的MOVE -> onTouch的MOVE ->
onTouchListener的UP -> onTouch的UP ->
onClick

现象二:onTouchListener、onTouch、onClick三个都有的情况下,并且onTouchListener返回true,表示自己处理事件,就不会把事件分发给子控件,所以就只会执行自己而方法;

03-25 08:25:30.493 23991-23991/? E/TAG: 触摸onTouch() -> 0
03-25 08:25:30.625 23991-23991/? E/TAG: 触摸onTouch() -> 2
03-25 08:25:30.625 23991-23991/? E/TAG: 触摸onTouch() -> 1

执行顺序如下:
onTouchListener的DOWN -> onTouchListener的MOVE -> onTouchListener的UP

现象三:只有 onTouchEvent()、onClickListener(),前提是onTouchEvent返回true,表示自己处理事件,就不会把事件分发下去,所以就只执行自己的方法,不会执行下边的方法;

03-25 09:19:11.648 3005-3005/? E/TAG: onTouchEvent -> 0
03-25 09:19:11.752 3005-3005/? E/TAG: onTouchEvent -> 2
03-25 09:19:11.752 3005-3005/? E/TAG: onTouchEvent -> 1

执行顺序如下:
onTouchEvent的DOWN -> onTouchEvent的MOVE -> onTouchEvent的UP,不会执行onClick事件

onClick不执行的原因:
因为onClick事件是在 View中的 onTouchEvent中的 case MotionEvent.ACTION_UP:里边调用了performClick(),而这里onTouchEvent返回的是true,而不是super.onTouchEvent(event),所以就不会执行View中的方法,所以就不会执行 View中的 onTouchEvent中的 case MotionEvent.ACTION_UP,所以onClick不会调用

现象四: onTouchListener onTouchEvent onClick dispatchTouchEvent 都有,前提是dispatchTouchEvent返回true,那么一个方法都不会执行;如果dispatchTouchEvent返回true,并且添加super.dispatchTouchEvent(event) ;那么现象和现象一是一样的。

public class MainActivity extends AppCompatActivity {

    private TouchView touchView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        touchView = (TouchView) findViewById(R.id.touch_view);
        touchView.setEnabled(false);  //touchView不可用


        touchView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG" , "onTouch -> "+event.getAction()) ;
                return false;
            }
        });
        touchView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG" , "onClick") ;
            }
        });

    }
}
public class TouchView extends View {
    public TouchView(Context context) {
        this(context, null);
    }

    public TouchView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TouchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TAG" , "onTouchEvent -> "+event.getAction()) ;
        return super.onTouchEvent(event);
    }


    /**
     *  复写 dispatchTouchEvent作用就是,在onTouchEvent()方法中可以返回任何值,return false、return true、return super.onTouchEvent(event)都是可以的
     *  但是在 dispatchTouchEvent必须返回true,并且添加super.dispatchTouchEvent(event) ,这样的话现象就是现象一
     * @param event
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        super.dispatchTouchEvent(event) ;
        Log.e("TAG" , "dispatchTouchEvent -> "+event.getAction()) ;
        return true;
    }
}


3. View和Touch相关的有2个非常重要的方法

3.1>:dispatchTouchEvent()事件分发:

源码分析:
在View源码中的 dispatchTouchEvent()方法中:

    public boolean dispatchTouchEvent(MotionEvent event) {        

        // result:默认是false
        boolean result = false;

            // ListenerInfo:里边存放了 View的所有的 Listener信息
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        return result;
    }

以上中:
boolean result = false;
ListenerInfo 很重要,它里边存放了View的所有的Listener信息,比如:onTouchListener、onClickListener

ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null               
   && (mViewFlags & ENABLED_MASK) == ENABLED
   && li.mOnTouchListener.onTouch(this, event)) {
       result = true;
}
分析以上代码可知:
li为true,li.mOnTouchListener != null 为true
(mViewFlags & ENABLED_MASK) == ENABLED 是否是ENABLE可用的
li.mOnTouchListener.onTouch(this, event):

如果返回false,说明进不去if语句,那么就直接用初始化的result = false的值;
如果返回true,那么 result = true ;

if (!result && onTouchEvent(event)) {
      result = true;
}
分析以上代码可知:

对于if (!result && onTouchEvent(event)) :
如果上边的result为false,那么 !result为true,那么就会执行后边的 onTouchEvent()方法了;
如果 result为true,那么 !result为false,那么就不会执行后边的 onTouchEvent()方法了;

到目前来讲,我们都还没有看到点击事件?
在View的onTouchEvent中的 case MotionEvent.ACTION_UP里边调用了 performClick()方法,点击 performClick()进入里边方法后,具体代码是:

public boolean performClick() {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }

        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
        return result;
    }

分析:因为onTouchEvent返回true,即return true ,而没有return super.onTouchEvent(event),所以就不会执行View,更不会执行View中的onTouchEvent中的case MotionEvent.ACTION_UP,所以就只会执行 onTouchEvent()的Down、Move、Up事件,不会执行onClick()方法了;

3.2>:onTouchEvent(),这个方法一般都被我们复写,并且直接return true即可;

注意:

注意:自定义View是没有 onInterceptTouchEvent() 拦截方法的

4. 总结如下:


  • 如果onTouchListener返回false,表示不处理事件,把事件分发给子控件,让下级处理,执行顺序就是:
    onTouchListener、onTouchEvent、onClickListener
  • 如果onTouchListener返回true,表示自己处理事件,就不会把事件分发给子控件,所以就只会执行onTouchListener

相关文章

  • 有关view的事件分发

    事件分发:用户点击屏幕(view或者viewGroup)产生点击事件(touch事件),touch事件的(发生触摸...

  • Touch分发的结论

    Touch传递 Touch事件先传递到Activity,然后ViewGroup,再传递到View。 Touch分发...

  • Android事件分发机制

    基础知识 事件分发的对象 事件分发的对象是 点击事件(Touch事件),当用户触摸屏幕(View或者ViewGro...

  • Android事件分发

    在看事件分发之前,先看一下View、ViewGroup、Activity的对Touch事件的处理。 一、View对...

  • Android基础(28)事件分发

    1)请描述一下View事件传递分发机制2)Touch事件传递流程3)事件分发中的onTouch 和onTouchE...

  • 再论Android的事件分发机制

    Touch事件分发中只有两个主角:ViewGroup和View。Activity的Touch事件事实上是调用它内部...

  • View的Touch事件分发

    1. 说明 这节课我们就来分析系View的Touch事件分发的顺序。 2. 分析 现象一:onTouc...

  • Android 事件分发总结

    一、View事件分发 先看看这几种现象 View与Touch事件相关的两个方法 1.1 dispatchTouch...

  • Android View的Touch事件分发

    事件分发的重要性我就不多说了,我们先从简到难。先看View的Touch事件分发,我自定义一个View,重写OnTo...

  • Android View的事件分发

    View的事件分发所针对的是MotionEvent事件,在Touch过程中会产生大量的MotionEvent,记录...

网友评论

    本文标题:View的Touch事件分发

    本文链接:https://www.haomeiwen.com/subject/dwqhcftx.html