注册

Activity 感知 Fragment 中的触摸事件

前言


FragmentActivity 上,发现 Fragment 上的触摸事件会被 Activity 所接收。这在一些业务场景上很不适用,很多时候业务逻辑不想让我们Fragment中的触摸事件被Activity所感知,那应该怎么做呢?


举个例子吧


我们先建一个Activity,然后在Activity上放一个FragmentFragment位于整个屏幕的下半部分,然后尝试在Fragment上点击,滑动,这时Activity可以接收到这些触摸事件吗?


先将这个Demo的代码写出来:


先为 MainActivity 布局,将我们的Fragment位于整个屏幕的下半部分。


MainActivity.java

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="<http://schemas.android.com/apk/res/android>"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/color_text_gray_light"
android:textSize="16sp"
android:layout_weight="1" />

<androidx.fragment.app.FragmentContainerView
android:id="@+id/liTestFcv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:name="com.jmkj.VirtualCurrency.Home.Fragment.LiTestFragment"/>

</LinearLayout>

然后为我们的Fragment布局,这里取名为 LiTestFragment,放两个Button,其余空间都空着,方便后续的点击、滑动等触摸事件处理。


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="<http://schemas.android.com/apk/res/android>"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="button 1" />

<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="button 2" />

</LinearLayout>

并且为这两个按钮添加点击事件,点击跳出Toast提示。


btn1.setOnClickListener {
Toast.makeText(context, "btn 1 click", Toast.LENGTH_SHORT).show()
}
btn2.setOnClickListener {
Toast.makeText(context, "btn 2 click", Toast.LENGTH_SHORT).show()
}

接着,我们在 MainActivity.java 中重写 onTouchEvent 方法,进行对触摸事件的拦截。


@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "onTouchEvent: ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "onTouchEvent: ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "onTouchEvent: ACTION_UP");
break;

}
return true;
}

猜想一下:


当我们在LiTestFragment的空白区域进行点击、滑动时,MainActivity可以接收到这些触摸事件吗?


答案:可以收到。


当我们在 LiTestFragment 空白区域滑动时,输出日志如下:


E/MainActivity: onTouchEvent: ACTION_DOWN
E/MainActivity: onTouchEvent: ACTION_MOVE
E/MainActivity: onTouchEvent: ACTION_MOVE
E/MainActivity: onTouchEvent: ACTION_MOVE
E/MainActivity: onTouchEvent: ACTION_MOVE
E/MainActivity: onTouchEvent: ACTION_MOVE
E/MainActivity: onTouchEvent: ACTION_MOVE
E/MainActivity: onTouchEvent: ACTION_UP

那再猜想一下:


当我点击LiTestFragment 中的两个按钮时,MainActivity可以接收到这两个点击事件吗?


答案:收不到。


这是为什么呢?思考一下。


那如果我们想让在Fragment中的触摸事件不被Activity接收到,那又该怎么做呢?


Fragment中先行一步拦截掉,然后将触摸事件消费掉,这样就可以避免该触摸事件被Activity所接收到。


override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_li_test, container, false)
view?.setOnTouchListener { v, event ->
v.performClick()
true
}
...省略代码...

return view
}

这里 v.performClick() 为调用该视图定义的 OnClickListener 方法,返回true就是代表消耗该触摸事件。这样子,触摸事件就将在Fragment中被消耗,所以MainActivity也就收不到该触摸事件了。


这里我们回到刚刚的问题,为什么我在LiTestFragment中点击两个按钮时,MainActivity收不到该触摸事件?


因为这里我们是为整个Fragment添加触摸事件监听,而我们的两个按钮就是该Fragment的子view


当我们点击按钮时,触发其onTouchEvent,然后执行 performClick(),执行mOnClickListener.onClick(this),也就是我们为按钮添加的点击监听事件。


所以,如果我们不想让按钮的点击监听事件工作的话,我们只需要为按钮设置OnTouchEvent,然后将事件消费掉就可以了。


findViewById<Button>(R.id.btn1).apply {
setOnTouchListener { v, event ->
Log.e(TAG, "operation: btn1 onTouchListener")
true
}

setOnClickListener {
Toast.makeText(context, "btn 1 click", Toast.LENGTH_SHORT).show()
}
}

总结


其实本文所述的内容都是属于Android事件分发的知识点,想要更好的理解本文,更好的理解ActivityFragment以及子View之间的触摸事件传递,就需要进一步学习一下Android事件分发知识点,我会在下一篇文章中做进一步分享。


作者:乐黎
链接:https://juejin.cn/post/7103823632958226469
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册