美文网首页
View事件分发(二)-View事件分发(源码分析)

View事件分发(二)-View事件分发(源码分析)

作者: 如愿以偿丶 | 来源:发表于2020-10-29 14:43 被阅读0次

1.View的事件分发两个重要方法

1.1.dispatchTouchEvent
1.2.onTouchEvent

2.通过上述两个方法阅读源码

2.1.View的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) {
        ...
        boolean result = false;

        if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //1.ListenerInfo存放所有listen的信息,如OnTouchListener,onClickListener等
            ListenerInfo li = mListenerInfo;
            /**
              * 2.返回result为true条件
              *  1.ListenerInfo不为空
              *  2.onTouchListener不为空
              *  3.(mViewFlags & ENABLED_MASK) == ENABLED 表示View的enable为true
              *  4.onTouchListener.onTouch为true
              */
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
            
           /**
             * 3.返回result为true条件
             *  1.result为false时
             *  2.onTouchEvent返回true
             */
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }

       ...
        return result;
    }

由源码可知:

1.当调用View的dispatchTouchEvent的时候,首先会查看ListenerInfo信息。通过ListenerInfo可知View的事件执行
2.当onTouchListener.onTouch返回true时,result为true,此时就不会执行onTouchEvent方法。
3.当onTouchListener.onTouch返回false时,result为false,此时执行onTouchEvent方法。

通过代码测试

1.布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".twelve.ScalableActivity">

        <com.yc.drawdashboard.touch.TouchView
            android:id="@+id/touchview"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:background="@color/colorPrimary"/>
</LinearLayout>

2.自定义一个TouchView,重写dispatchTouchEvent,onTouchEvent

public class TouchView extends View {

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        return super.dispatchTouchEvent(event);
    }

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

3.主页面代码,添加onTouchListener,onClickListener

public class ScalableActivity extends AppCompatActivity {
    
    private TouchView mTouchView;

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

        mTouchView = findViewById(R.id.touchview);

        //添加onTouchListener,onTouch返回默认false
        mTouchView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG","onTouch----"+event.getAction());
                return false;
            }
        });

        //添加onClickListener
        mTouchView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TAG","onClick");
                Toast.makeText(ScalableActivity.this,"onClick",Toast.LENGTH_SHORT).show();
            }
        });
    }
}

第一种情况:

当View的dispatchTouchEvent,onTouchListener.onTouch,onTouchEvent,onClickListener时,都返回默认值时
执行顺序:

dispatchTouchEvent按下
onTouch按下
onTouchEvent按下
dispatchTouchEvent移动
onTouch移动
onTouchEvent移动
dispatchTouchEvent抬起
onTouch抬起
onTouchEvent抬起
onClick

动画效果:

image_one.gif

第二种情况:

当View的dispatchTouchEvent,onTouchListener.onTouch,onTouchEvent,onClickListener返回默认值时,只有dispatchTouchEvent去掉super.dispatchTouchEvent(event),直接返回true或false,其他都不变

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("TAG","dispatchTouchEvent----"+event.getAction());
        return true; //或者false
    }

执行顺序:

dispatchTouchEvent按下
dispatchTouchEvent移动
dispatchTouchEvent抬起

动画效果:

image_two.gif

第三种情况:

当View的dispatchTouchEvent,onTouchListener.onTouch,onTouchEvent,onClickListener返回默认时,只有onTouchListener.onTouch返回true,其他都不变

    //添加onTouchListener,onTouch返回默认false
        mTouchView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("TAG","onTouch----"+event.getAction());
                return true;
            }
        });

执行顺序:

dispatchTouchEvent按下
onTouch按下
dispatchTouchEvent移动
onTouch移动
dispatchTouchEvent抬起
onTouch抬起
不执行onTouchEvent和onClickListener

动画效果:

image_three.gif

第四种情况

当View的dispatchTouchEvent,onTouchListener.onTouch,onTouchEvent,onClickListener返回默认时,只有onTouchEvent返回true,其他都不变

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

执行顺序:

dispatchTouchEvent按下
onTouch按下
onTouchEvent按下
dispatchTouchEvent移动
onTouch移动
onTouchEvent移动
dispatchTouchEvent抬起
onTouch抬起
onTouchEvent抬起
不执行onClickListener

动画效果:

image_four.gif

第五种情况:

当有onTouchListener.onTouch,onTouchEvent,onClickListener时,onTouch返回false,onTouchEvent返回false,其他都不变

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

执行顺序:

dispatchTouchEvent按下
onTouch按下
onTouchEvent按下
后续手指移动,手指抬起等所有事件都不执行

动画效果:

image_five.gif

第七种情况:

当有onTouchListener.onTouch,onTouchEvent,onClickListener时,onTouch返回false,onTouchEvent调用super.onTouchEvent(event),并且返回false,其他都不变

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

执行顺序:

dispatchTouchEvent按下
onTouch按下
onTouchEvent按下
后续手指移动,手指抬起等所有事件都不执行

动画效果:

image_five.gif

第八种情况:

当有onTouchListener.onTouch,onTouchEvent,onClickListener时,onTouch返回false,onTouchEvent调用super.onTouchEvent(event),并且返回false,其他都不变

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

执行顺序:

dispatchTouchEvent按下
onTouch按下
onTouchEvent按下
dispatchTouchEvent移动
onTouch移动
onTouchEvent移动
dispatchTouchEvent抬起
onTouch抬起
onTouchEvent抬起
onClick

动画效果:

image_six.gif

第九种情况:

当有onTouchListener.onTouch,onTouchEvent,onClickListener时,onTouch返回false,onTouchEvent调用super.onTouchEvent(event),ACTION_DOWN(按下事件)返回false,ACTION_MOVE,ACTION_UP返回true,其他都不变

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TAG","onTouchEvent----"+event.getAction());
        super.onTouchEvent(event);
        boolean result = false;
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:    //按下事件返回false
                result = false;
                break;
            case MotionEvent.ACTION_MOVE:
                result = true;
                break;
            case MotionEvent.ACTION_UP:
                result = true;
                break;
        }
        return result;
    }
}

执行顺序:

dispatchTouchEvent按下
onTouch按下
onTouchEvent按下
后续手指移动,手指抬起等所有事件都不执行

动画效果:

image_five.gif

第十种情况:

当有onTouchListener.onTouch,onTouchEvent,onClickListener时,onTouch返回false,onTouchEvent调用super.onTouchEvent(event),ACTION_DOWN(按下事件)返回true,ACTION_MOVE,ACTION_UP返回false,其他都不变

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("TAG","onTouchEvent----"+event.getAction());
        super.onTouchEvent(event);
        boolean result = false;
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:    //按下事件返回true
                result = true;
                break;
            case MotionEvent.ACTION_MOVE:
                result = false;
                break;
            case MotionEvent.ACTION_UP:
                result = false;
                break;
        }
        return result;
    }
}

执行顺序:

dispatchTouchEvent按下
onTouch按下
onTouchEvent按下
dispatchTouchEvent移动
onTouch移动
onTouchEvent移动
dispatchTouchEvent抬起
onTouch抬起
onTouchEvent抬起
onClick

动画效果:

image_seven.gif

3.总结:View的dispatchTouchEvent,onTouchListener.onTouch,onTouchEvent,onClickListener之间的关系。

结合源码和上述测试结果可知:
  1.调用onTouchListener.onTouch的前提下,View的dispatchTouchEvent必须调用super.dispatchTouchEvent。

  2.调用onTouchEvent的前提下,View的onTouchListen.onTouch必须返回false并且enable属性为false。

  3.调用onClickListener的前提下,View的onTouchEvent必须调用super.onTouchEvent(event)并且ACTION_DOWN必须返回true。

相关文章

网友评论

      本文标题:View事件分发(二)-View事件分发(源码分析)

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