美文网首页
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