赞
踩
【5年Android从零复盘系列之十四】Android自定义View(9):事件分发&处理
三者关系伪代码
public boolean dispatchTouchEvent(MotionEvent event){
boolean consume = false;
if( onInterceptTouchEvent(event) ){
consume = onTouchEvent(event);
}else{
consume = child.dispatchTouchEvent(event);
}
return consume;
}
用来进行事件分发;
返回值表示是否下分发本次事件【默认的返回值子view的dispatchTouchEvent()的返回值】
用于判断是否拦截某个事件序列;
返回值表示是否拦截本次事件【默认false】
用于处理事件;
返回值表示是否消耗本次事件【默认true】
如果不消耗,则同一事件序列,当前View无法再次接收到事件event,即该情况下不再被调用
当前View如果设置了OnTouchListener,事件分发当前View时,OnTouchListener的【onTouch()】方法会被先调用。
如果OnTouchListener的【onTouch()】返回值为false,那么会继续调用「onTouchEvent()」;反之return true,则不会调用「onTouchEvent()」;
在「onTouchEvent()」中,如果View设置了OnClickListener,则其中的[onClick()]会被最后调用,该方法优先级最低,事件传递的末端。
同一事件序列:
指的是,从手指接触屏幕的那一刻开始,直至手指离开屏幕一刻结束。
以ACTION_DOWN开始,以ACTION_UP结束,中间0或∞个ACTION_MOVE
正常情况,一个事件序列只能被一个View拦截&&消耗。特殊情况,可以强行传递给其他View处理。
一个事件序列,一旦被某个View拦截,那么只能由该View处理,且onInterceptTouchEvent不会再次调用,即不再多余询问是否拦截。
当View开始处理事件,如果一开始的ACTION_DOWN事件未消耗,即【onTouchEvent()】返回了false,那么本次事件序列的后续事件【都不会】再交给该View处理,并且事件向上回流给父View的onTouchEvent()处理。
如果View只消耗ACTION_DOWN事件,而不消耗其他触摸事件,则这个事件会消失;且 父View的onTouchEvent()不会被调用;且这些事件最终将交由Activity处理
单纯的View控件,没有onInterceptTouchEvent()方法,事件分发到View,【onTouchEvent()】会被调用。「Activity也没有onInterceptTouchEvent()」
ViewGroup比View多了一个onInterceptTouchEvent(),默认不拦截任何事件,即默认return false
onTouchEvent()默认消耗事件 return true;特殊情况返回false:View被设置了clickable = = false && longClickable = = false。(longClickable默认就是false)「Button默认clickable = = true,TextView默认clickable = = false」
View的enable属性值,不影响onTouchEvent()的默认返回值true,clickable = = true || longClickable = = true 时 --> onTouchEvent()就默认return true;
View的enable属性值,会影响onTouchListener,enable = = false时,onTouchListener.onTouch()不会被执行
requestDisallowInterceptTouchEvent()可以在子View中干预【所有父View】的事件分发
先上一次正常的【点击事件】的事件分发+处理的log结果
ViewTestCCC.java
public class ViewTestCCC extends View { @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.e("touch_test","===== ViewTestCCC.dispatchTouchEvent ===="); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e("touch_test","===== ViewTestCCC.onTouchEvent ===="); return super.onTouchEvent(event); } public ViewTestCCC(Context context) { super(context); } public ViewTestCCC(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public ViewTestCCC(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public ViewTestCCC(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } }
ViewGroupBBB.java
public class ViewGroupBBB extends RelativeLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.e("touch_test","===== ViewGroupBBB.dispatchTouchEvent ===="); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e("touch_test","===== ViewGroupBBB.onInterceptTouchEvent ===="); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e("touch_test","===== ViewGroupBBB.onTouchEvent ===="); return super.onTouchEvent(event); } public ViewGroupBBB(Context context) { super(context); } public ViewGroupBBB(Context context, AttributeSet attrs) { super(context, attrs); } public ViewGroupBBB(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public ViewGroupBBB(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } }
ViewGroupAAA.java
public class ViewGroupAAA extends RelativeLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.e("touch_test","===== ViewGroupAAA.dispatchTouchEvent ===="); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e("touch_test","===== ViewGroupAAA.onInterceptTouchEvent ===="); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e("touch_test","===== ViewGroupAAA.onTouchEvent ===="); return super.onTouchEvent(event); } public ViewGroupAAA(Context context) { super(context); } public ViewGroupAAA(Context context, AttributeSet attrs) { super(context, attrs); } public ViewGroupAAA(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public ViewGroupAAA(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } }
Activity的布局文件.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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=".BaseSuperResourceActivity"> <com.cupster.base_super_resource.ViewGroupAAA android:layout_width="500dp" android:layout_height="500dp" android:background="@android:color/holo_red_light" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" > <com.cupster.base_super_resource.ViewGroupBBB android:layout_centerInParent="true" android:layout_width="300dp" android:layout_height="300dp" android:background="@android:color/holo_green_light" > <com.cupster.base_super_resource.ViewTestCCC android:id="@+id/view_ccc" android:layout_centerInParent="true" android:background="@android:color/holo_orange_light" android:layout_width="150dp" android:layout_height="150dp" /> </com.cupster.base_super_resource.ViewGroupBBB> </com.cupster.base_super_resource.ViewGroupAAA> </androidx.constraintlayout.widget.ConstraintLayout>
activity
public class BaseSuperResourceActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base_super_resource); View viewCCC = findViewById(R.id.view_ccc); viewCCC.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { Log.e("touch_test","===== ViewTestCCC.[[OnTouchListener]].onTouch() ===="); return false; } }); viewCCC.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.e("touch_test","===== ViewTestCCC.<<OnClickListener>>.onClick() ===="); } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.e("touch_test","===== Activity.dispatchTouchEvent ===="); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.e("touch_test","===== Activity.onTouchEvent ===="); return super.onTouchEvent(event); } }
正常点击事件的节点日志
viewCCC.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.e("touch_test","===== ViewTestCCC.[[OnTouchListener]].onTouch() ====");
return true;//消费该事件,则不再继续分发流程
}
});
结果:不再调用【onTouchEvent()】,OnTouchListener优先级比【onTouchEvent()】高
2.修改ViewTestCCC.java的【onTouchEvent()】的返回值为false:即 不处理
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("touch_test","===== ViewTestCCC.onTouchEvent ====");
// return super.onTouchEvent(event);
return false;
}
结果:因为ViewGroupBBB、ViewGroupAAA的【onTouchEvent()】直接return super.onTouchEvent(),所以当View的【onTouchEvent()】未处理事件,事件将逐级回送给父view去处理,
3.修改ViewGroupBBB.java的【onInterceptTouchEvent】拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("touch_test","===== ViewGroupBBB.onInterceptTouchEvent ====");
return true;
}
结果:自身拦截了事件,则调用自身【onTouchEvent()】处理事件
4.在3.的基础上,【onTouchEvent()】返回true:自身消费事件,则不再继续回送父view处理
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("touch_test","===== ViewGroupBBB.onInterceptTouchEvent ====");
// return super.onInterceptTouchEvent(ev);
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("touch_test","===== ViewGroupBBB.onTouchEvent ====");
// return super.onTouchEvent(event);
return true;
}
结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。