透明Activity中TextView设点击监听且背景应用可交互的实现问题
问题分析与解决方案
你的核心问题出在Window标记的设置上:你给当前Activity的Window添加了FLAG_NOT_TOUCHABLE,这个标记会让整个窗口完全不接收任何触摸事件,所以即使你给TextView设置了点击监听,也永远不会触发。
而你需要的效果是:TextView可点击,同时背景应用能正常交互,我们可以通过以下步骤实现:
1. 调整Window标记
首先移除FLAG_NOT_TOUCHABLE,保留另外两个必要的标记:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 移除 FLAG_NOT_TOUCHABLE,让窗口可以接收触摸事件 getWindow().addFlags( WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); setContentView(R.layout.activity_main); // 后续代码... }
FLAG_NOT_FOCUSABLE:让窗口不获取焦点,确保背景应用可以接收按键等事件FLAG_NOT_TOUCH_MODAL:窗口不会拦截不属于它的触摸事件,但默认情况下根布局还是会消费事件,所以需要下一步处理
2. 给根布局添加触摸过滤
我们需要让根布局只在触摸到TextView的时候,才把事件传递给TextView;其他区域的触摸事件直接透传给背景应用。
首先给XML中的根布局添加id:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/root_layout" <!-- 添加这个id --> android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent"> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
然后在Java代码中给根布局设置触摸监听:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags( WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); setContentView(R.layout.activity_main); tv = findViewById(R.id.tv); ConstraintLayout rootLayout = findViewById(R.id.root_layout); // 设置TextView点击监听 tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(MainActivity.this, "clicked", Toast.LENGTH_SHORT).show(); } }); // 根布局触摸过滤 rootLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // 获取TextView在屏幕上的坐标范围 int[] tvLocation = new int[2]; tv.getLocationOnScreen(tvLocation); int tvLeft = tvLocation[0]; int tvTop = tvLocation[1]; int tvRight = tvLeft + tv.getWidth(); int tvBottom = tvTop + tv.getHeight(); // 获取触摸点的绝对坐标 float touchX = event.getRawX(); float touchY = event.getRawY(); // 判断触摸点是否在TextView范围内 if (touchX >= tvLeft && touchX <= tvRight && touchY >= tvTop && touchY <= tvBottom) { // 让TextView处理事件,返回false表示不消费事件,传递给子View return false; } else { // 消费事件并透传给背景应用,返回true表示已处理 return true; } } }); }
原理说明
- 移除
FLAG_NOT_TOUCHABLE后,窗口可以接收触摸事件 FLAG_NOT_TOUCH_MODAL确保窗口不会强制拦截所有触摸- 通过根布局的触摸监听,我们手动判断触摸区域:只有触摸到TextView时,才让事件传递给它;其他区域直接透传,这样背景应用就能正常响应点击了。
内容的提问来源于stack exchange,提问作者Kylo Ren
相关产品推荐
相关产品推荐

