Android TV端弹出的PopupWindow没有获取焦点

在 TV 开发中,焦点管理是通过 Focus Navigation 实现的,PopupWindow 默认不接受焦点,导致遥控器无法选择弹窗内的控件。这是因为 PopupWindow 默认不会将焦点传递到其内容视图上。

要解决问题,可以通过以下步骤调整 PopupWindow 的焦点行为。


解决方法

确保 PopupWindow 的 focusable 属性为 true,并强制让其内容视图可以获取焦点。

在 BasePopupWindow 的构造函数中添加以下代码:

java 复制代码
setFocusable(true); // 允许 PopupWindow 获取焦点
setOutsideTouchable(false); // 禁止点击外部关闭(可选,根据需求调整)

完整代码修改:

java 复制代码
public BasePopupWindow(Context context, int layoutResId, int width, int height, boolean focusable) {
    super(width, height, focusable);
    binding = DataBindingUtil.inflate(LayoutInflater.from(context), layoutResId, null, false);
    setContentView(binding.getRoot());
    setBackgroundDrawable(new ColorDrawable(0x00000000)); // 默认背景透明
    setFocusable(true); // 确保弹窗获取焦点
    setOutsideTouchable(false); // 避免点击外部时关闭,保证焦点
    initialize(); // 子类实现具体逻辑
}

2. 强制请求焦点到弹窗的内容

在 LogoutPopupWindow 的 initialize 方法中,调用 requestFocus() 将焦点移动到弹窗的按钮上。

java 复制代码
@Override
protected void initialize() {
    // 设置动态文案
    binding.tvMessage.setText(username + ",是否退出登录?");

    // 设置按钮点击事件
    binding.btnConfirm.setOnClickListener(v -> {
        Toast.makeText(binding.getRoot().getContext(), username + "已退出登录", Toast.LENGTH_SHORT).show();
        dismissPopup();
    });

    binding.btnCancel.setOnClickListener(v -> dismissPopup());

    // 强制将焦点设置到退出按钮上
    binding.btnConfirm.post(() -> binding.btnConfirm.requestFocus());
}

3. 确保布局中的控件支持焦点

在 popup_logout.xml 中,确保按钮和其他交互控件明确声明支持焦点和点击事件:

xml 复制代码
<Button
    android:id="@+id/btn_confirm"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="退出登录"
    android:focusable="true"
    android:clickable="true"
    android:backgroundTint="@android:color/holo_red_light"
    android:textColor="@android:color/white"
    android:layout_marginTop="8dp" />

<Button
    android:id="@+id/btn_cancel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="取消"
    android:focusable="true"
    android:clickable="true"
    android:backgroundTint="@android:color/darker_gray"
    android:textColor="@android:color/white"
    android:layout_marginTop="8dp" />

4. 使用 WindowManager.LayoutParams 设置焦点模式

确保 PopupWindow 在显示时优先处理焦点事件。可以在弹窗显示时配置 WindowManager.LayoutParams:

java 复制代码
@Override
public void showAtLocation(View parent, int gravity, int x, int y) {
    super.showAtLocation(parent, gravity, x, y);
    getContentView().setFocusable(true); // 内容允许聚焦
    getContentView().setFocusableInTouchMode(true);
}

完整流程

  1. 在 BasePopupWindow 中:
    • 确保 setFocusable(true) 和 setOutsideTouchable(false)。
  2. 在布局文件中:
    • 明确声明交互控件支持焦点和点击事件。
  3. 在 initialize() 方法中:
    • 使用 requestFocus() 将初始焦点设置到弹窗内的某个控件。
  4. 在 showAtLocation 或 showAsDropDown 中:
    • 确保视图允许焦点和触摸模式。

完成这些步骤后,弹出的 PopupWindow 就会正确响应 TV 遥控器的焦点导航。

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui