Android 事件分发机制详解与实战剖析 | 开发者说·DTalk
本文原作者: 门心叼龙,原文发布于: https://blog.csdn.net/geduo_83/article/details/86560896
本文为自己多年来在 Android 实战开发过程中总结归纳的一些常见问题,现在分享出来希望对初学者有所帮助。
事件分发是 Android 开发过程中的重点又是难点, 一张事件分发流程图,让你彻底搞明白。网上有很多文章写事件分发,感觉都没有讲明白,恭喜你,今天你看到好文章了,你彻底搞清楚…
目录
1.在 Android 操作系统中,拥有事件传递功能的类都有哪些?2.触摸事件的类型?3.事件传递的三个阶段?4.简述 View 的事件传递机制?5.简述 ViewGroup 的事件传递机制?6.事件分发流程图7.实战案例
1.在 Android 操作系统中,拥有事件传递功能的类都有哪些?
Activity: 拥有 dispathTouchEvent 和 onTouchEvent 方法
View: 拥有 dispathTouchEvent 和 onTouchEvent 方法
ViewGroup: 拥有 dispatchTouchEvent、onTouchEvent、onInterceptTouchEvent
2.触摸事件的类型?
主要有三种:
ACTION_DOWN: 手指的按下操作
ACTION_MOVE: 手指按下后,松开手之前,轻微移动所触发的事件
ACTION_UP: 手指离开屏幕的操作
3.事件传递的三个阶段?
3.1 按照事件进行划分
3.2 按照 View 进行划分
结论: 无论是 View 还是 ViewGroup,不管他是 DispatchTouchEvent 还是 onTouchEvent 方法,方法返回 true、返回 false 的处理逻辑都是一样的,只是调用父类的同名方法的时候处理的逻辑有所不同,View 偏重消费、ViewGourp 偏重分发。
4.简述 View 的事件传递机制?
触摸事件的传递流程是从 dispatchTouchEvent 开始的,如果不进行人工干预,则事件将会依照 View 树的嵌套层次从外层向内层传递,到达最内层的 View 时,就由它的 onTouchVent 方法处理。
如果事件在传递过程中,进行了人工干预,事件分发函数返回 true 表示自行消费,返回父类的同名方法则该事件传递给自身的 onTouchEvent 进行处理,返回 false 表示该事件会回传给父 view 的 onTouchEvent 方法进行处理,此时后面的事件都接受不到了,最后由哪个 View 处理,以后的所有事件都交由它来处理。
如果事件在传递过程中,进行了人工干预,事件处理函数,返回 true 和调用同名方法表示该事件被消费,返回 false 则表示该事件回传给父类的同名方法进行处理。
事件触发是先触发 onTouch,再触发 onClick,如果 onTouch 方法返回 true,表示消费掉该事件,不在继续进行事件传递,onClick 也不会被调用,如果 onTouch 方法返回 false,则继续会事件传递,onClick 会被调用。
5.简述 ViewGroup 的事件传递机制?
触摸事件的传递顺序是由 Activity 到 ViewGroup,再由 ViewGroup 递归传递给他的子 View,ViewGroup 通过 onInterceptTouchEvent 方法对事件进行拦截,如果该方法返回 true,则事件不会继续往下传递给子 View,如果返回 false 或者是调用 super.onInterceptTouchEvent,则事件会继续会传递给子 View。
如果事件在传递过程中,进行了人工干预,事件分发函数返回 true 表示事件被自行消费,返回 false,则回传给父 View 的 onTouchEvent 进行处理,此时后面的事件都接受不到了,调用同名方法则继续传递。
如果事件在传递过程中,进行了人工干预,事件处理函数,返回 true 则表示该事件被消费,返回 false 和调用同名方法则表示该事件回传给父类的同名方法进行处理。
6.事件分发流程图
一张 Android 事件分发流程,让你彻底搞明白 Android 的事件分发机制。
7.实战案例
实现效果如下,底部的行程详情可以往上拖动覆盖在地图之上,也可以往下拖动停止在屏幕的正中位置,地图相关操作: 放大、缩小、移动都能正常的响应,怎么实现?下面就是具体的源码实现过程。
7.1 事件分发处理
mTransparentView = findViewById(R.id.view_tansparent);
mTransparentView.setListener(new TransparentView.TouchEventListener() {
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return mMapView.dispatchTouchEvent(event);
}
});
mScrollView = findViewById(R.id.view_scrollview);
mScrollView.setListener(new TransparentView.TouchEventListener() {
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Rect rect = new Rect();
mTransparentView.getLocalVisibleRect(rect);
if(rect.contains((int)event.getX(),(int)event.getY())){
return true;
}else{
return false;
}
}
});
7.2 自定义 ViewTransparentView
public class TransparentView extends View {
TouchEventListener mListener;
public interface TouchEventListener{
boolean dispatchTouchEvent(MotionEvent event);
}
public TransparentView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if(mListener != null){
return mListener.dispatchTouchEvent(event);
}else{
return super.dispatchTouchEvent(event);
}
}
public void setListener(TouchEventListener listener) {
mListener = listener;
}
}
7.3 自定义 TransScrollView
public class TransScrollView extends NestedScrollView {
public TransparentView.TouchEventListener mListener;
public TransScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mListener != null && mListener.dispatchTouchEvent(ev)) {
return false;
}
return super.onInterceptTouchEvent(ev);
}
public void setListener(TransparentView.TouchEventListener listener) {
mListener = listener;
}
}
7.4 布局文件
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.amap.api.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="250dp"
/>
<com.zhijiaxing.travel.trip.record.view.TransScrollView
android:id="@+id/view_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<com.zhijiaxing.travel.trip.record.view.TransparentView
android:id="@+id/view_tansparent"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="#00000000"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical"
>
</LinearLayout>
</LinearLayout>
</com.zhijiaxing.travel.trip.record.view.TransScrollView>
</FrameLayout>
"开发者说·DTalk" 面向中国开发者们征集 Google 移动应用 (apps & games) 相关的产品/技术内容。欢迎大家前来分享您对移动应用的行业洞察或见解、移动开发过程中的心得或新发现、以及应用出海的实战经验总结和相关产品的使用反馈等。我们由衷地希望可以给这些出众的中国开发者们提供更好展现自己、充分发挥自己特长的平台。我们将通过大家的技术内容着重选出优秀案例进行谷歌开发技术专家 (GDE) 的推荐。
点击屏末 | 阅读原文 | 了解更多 "开发者说·DTalk" 活动详情与参与方式
长按右侧二维码
报名参与
本文地址:https://blog.csdn.net/jILRvRTrc/article/details/100135302
上一篇: linux基本命令手册
下一篇: Linux基础命令---dump