View的事件分发机制
1 点击事件的传递规则
当一个点击事件(MotionEvent)产生后,系统需要把这个事件传递给一个具体的View,这个传递的过程就是分发过程。
点击事件的分发过程涉及三个很重要的方法:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。
dispatchTouchEvent ( MotionEvent event )用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件。
onInterceptTouchEvent ( MotionEvent event )在dispatchTouchEvent方法中调用,用来判断是否拦截某个事件,如果当前View 拦截了某个事件,那么在同一个事件系列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。
onTouchEvent ( MotionEvent event )在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接收到事件。
ViewGroup 事件传递的伪代码 public boolean dispatchTouchEvent(MotionEvent ev) { // 默认事件没有被消费 boolean consume = false; if (onInterceptTouchEvent(ev)){ // 拦截事件,交给自身处理,调用自身onTouchEvent方法 consume=onTouchEvent(ev); }else { // 不拦截事件,交给子View处理,子View的dispatchTouchEvent方法会被调用 consume=child.dispatchTouchEvent(ev); } return consume; } OnTouchListener、onTouchEvent、OnClickListener事件传递优先级1 、默认情况
自定义Button:
@SuppressLint("AppCompatCustomView") public class viewTestButton extends Button { public viewTestButton(Context context) { super(context); } public viewTestButton(Context context, AttributeSet attrs) { super(context, attrs); } public viewTestButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.e("MainActivity", "onTouchEvent:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e("MainActivity", "onTouchEvent:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e("MainActivity", "onTouchEvent:ACTION_UP"); break; } return super.onTouchEvent(event); } }MainActivity 类:
@SuppressLint("ClickableViewAccessibility") public class MainActivity extends AppCompatActivity{ private static final String TAG = "MainActivity"; @BindView(R.id.btn) viewTestButton mBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); mBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e(TAG, "onClick:onClick"); } }); mBtn.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Log.e(TAG, "onTouch:ACTION_DOWN"); break; case MotionEvent.ACTION_MOVE: Log.e(TAG, "onTouch:ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.e(TAG, "onTouch:ACTION_UP"); break; } return false; } }); } }默认情况下onTouch 方法返回值是false ,onTouchEvent返回值是super.onTouchEvent(event)
日志:
com.example.viewtest E/MainActivity: onTouch:ACTION_DOWN com.example.viewtest E/MainActivity: onTouchEvent:ACTION_DOWN com.example.viewtest E/MainActivity: onTouch:ACTION_MOVE com.example.viewtest E/MainActivity: onTouchEvent:ACTION_MOVE com.example.viewtest E/MainActivity: onTouch:ACTION_UP com.example.viewtest E/MainActivity: onTouchEvent:ACTION_UP com.example.viewtest E/MainActivity: onClick:onClick2、只修改 onTouch 返回值为true
com.example.viewtest E/MainActivity: onTouch:ACTION_DOWN com.example.viewtest E/MainActivity: onTouch:ACTION_MOVE com.example.viewtest E/MainActivity: onTouch:ACTION_UP3、修改 onTouch 返回值为true , 修改onTouchEvent 返回值为true
com.example.viewtest E/MainActivity: onTouch:ACTION_DOWN com.example.viewtest E/MainActivity: onTouch:ACTION_MOVE com.example.viewtest E/MainActivity: onTouch:ACTION_UP3、修改 onTouch 返回值为true , 修改onTouchEvent 返回值为false
com.example.viewtest E/MainActivity: onTouch:ACTION_DOWN com.example.viewtest E/MainActivity: onTouch:ACTION_MOVE com.example.viewtest E/MainActivity: onTouch:ACTION_UP3、只修改onTouchEvent 返回值为true
com.example.viewtest E/MainActivity: onTouch:ACTION_DOWN com.example.viewtest E/MainActivity: onTouchEvent:ACTION_DOWN com.example.viewtest E/MainActivity: onTouch:ACTION_MOVE com.example.viewtest E/MainActivity: onTouchEvent:ACTION_MOVE com.example.viewtest E/MainActivity: onTouch:ACTION_UP com.example.viewtest E/MainActivity: onTouchEvent:ACTION_UP3、只修改onTouchEvent 返回值为false
com.example.viewtest E/MainActivity: onTouch:ACTION_DOWN com.example.viewtest E/MainActivity: onTouchEvent:ACTION_DOWN