如何检测AppCompatActivity标题栏触摸?解决FrameLayout监听失效问题
解决方案
一、检测标题栏的触摸事件
方法1:通过Activity事件分发拦截
重写Activity的dispatchTouchEvent(MotionEvent ev)方法,判断触摸坐标是否落在标题栏区域:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { // 计算标题栏总高度(状态栏+ActionBar) Rect rect = new Rect(); getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); int statusBarHeight = rect.top; int actionBarHeight = getSupportActionBar().getHeight(); int titleBarTotalHeight = statusBarHeight + actionBarHeight; // 判断触摸点是否在标题栏范围内 if (ev.getY() <= titleBarTotalHeight) { if (ev.getAction() == MotionEvent.ACTION_UP) { // 此处处理标题栏触摸逻辑 Toast.makeText(this, "标题栏被触摸", Toast.LENGTH_SHORT).show(); } } return super.dispatchTouchEvent(ev); }
方法2:用自定义Toolbar替代默认ActionBar
如果项目使用Toolbar(推荐方式),可直接给Toolbar设置触摸监听:
// 先在布局中添加Toolbar,再在Activity初始化 Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); toolbar.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { Toast.makeText(MainActivity.this, "Toolbar被触摸", Toast.LENGTH_SHORT).show(); } return true; // 根据需求决定是否消费事件 } });
二、解决FrameLayout触摸监听不触发的问题
你设置的setOnTouchListener未触发,是因为PreferenceFragmentCompat的布局完全覆盖了FrameLayout,触摸事件被子View(如Preference列表)消费了,可通过以下两种方式解决:
方法1:给FrameLayout添加透明顶层View
修改布局,在FrameLayout内添加全屏透明View,优先接收触摸事件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/fl" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 透明顶层View,用于捕获触摸 --> <View android:id="@+id/touch_catcher" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent"/> </FrameLayout> </LinearLayout>
然后在Activity中设置监听:
View touchCatcher = findViewById(R.id.touch_catcher); touchCatcher.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { RecyclerView preferenceRecyclerView = getView().findViewById(androidx.preference.R.id.recycler_view); if (preferenceRecyclerView != null) { Rect listRect = new Rect(); preferenceRecyclerView.getGlobalVisibleRect(listRect); // 判断触摸点是否在Preference列表下方空白区 if (event.getRawY() > listRect.bottom) { if (event.getAction() == MotionEvent.ACTION_UP) { Toast.makeText(getContext(), "空白区域被触摸", Toast.LENGTH_SHORT).show(); } return true; // 消费空白区事件 } } return false; // 其他区域事件传递给子View } });
方法2:重写PreferenceFragmentCompat的onTouchEvent
在自定义的PreferenceFragmentCompat子类中直接处理触摸事件:
public class MyPreferenceFragment extends PreferenceFragmentCompat { @Override public boolean onTouchEvent(MotionEvent event) { RecyclerView recyclerView = getView().findViewById(androidx.preference.R.id.recycler_view); if (recyclerView != null) { Rect listRect = new Rect(); recyclerView.getGlobalVisibleRect(listRect); if (event.getRawY() > listRect.bottom) { if (event.getAction() == MotionEvent.ACTION_UP) { Toast.makeText(getContext(), "空白区域被触摸", Toast.LENGTH_SHORT).show(); } return true; } } return super.onTouchEvent(event); } }
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

