前言
Fragment
在 Activity
上,发现 Fragment
上的触摸事件会被 Activity
所接收。这在一些业务场景上很不适用,很多时候业务逻辑不想让我们Fragment
中的触摸事件被Activity
所感知,那应该怎么做呢?
举个例子吧
我们先建一个Activity
,然后在Activity
上放一个Fragment
,Fragment
位于整个屏幕的下半部分,然后尝试在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事件分发的知识点,想要更好的理解本文,更好的理解Activity
、Fragment
以及子View
之间的触摸事件传递,就需要进一步学习一下Android事件分发知识点,我会在下一篇文章中做进一步分享。
网友评论