You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AndroidTV RecyclerView使用DPAD时如何监听焦点变化实现条目高亮

Android TV RecyclerView条目焦点变化监听实现方案

基础实现逻辑

RecyclerView本身未提供全局的条目焦点变化回调接口,最优实现方案是在ViewHolder初始化阶段为条目根布局绑定焦点监听器,性能损耗最低且逻辑最直接。

步骤1:确认条目布局基础配置

条目根布局需要先正确配置焦点相关属性:

  • 同时设置android:focusable="true"和android:focusableInTouchMode="true"
  • 若不需要子控件抢占焦点,可添加android:descendantFocusability="blocksDescendants"属性,确保焦点直接落在条目根布局上

步骤2:在ViewHolder中绑定焦点监听器

在ViewHolder的初始化代码中给条目根布局设置OnFocusChangeListener,即可监听每个条目的焦点变化,同时通过adapterPosition识别对应条目:

class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    init {
        itemView.setOnFocusChangeListener { view, hasFocus ->
            // 过滤ViewHolder未绑定到有效位置的异常场景
            val position = adapterPosition
            if (position == RecyclerView.NO_POSITION) return@setOnFocusChangeListener

            if (hasFocus) {
                // 条目获得焦点,执行高亮动画,示例为放大效果
                view.animate()
                    .scaleX(1.1f)
                    .scaleY(1.1f)
                    .setDuration(200)
                    .start()
                // 可通过position从数据源中获取当前焦点对应的条目数据
                val focusItem = dataList[position]
            } else {
                // 条目失去焦点,执行恢复动画
                view.animate()
                    .scaleX(1.0f)
                    .scaleY(1.0f)
                    .setDuration(200)
                    .start()
            }
        }
    }
}

注意:不要在onBindViewHolder方法中重复设置监听器,放在ViewHolder初始化逻辑中即可,避免重复创建监听实例造成性能浪费。

步骤3:可选:全局统一处理焦点逻辑

如果需要在Activity/Fragment层面统一处理焦点事件,可通过自定义回调接口将焦点事件向外抛出:

  1. 首先定义回调接口
interface OnItemFocusChangeListener {
    fun onItemFocusChanged(position: Int, hasFocus: Boolean, itemView: View)
}
  1. 在Adapter构造函数中传入回调实例
class MyAdapter(
    private val dataList: List<YourDataType>,
    private val focusListener: OnItemFocusChangeListener
) : RecyclerView.Adapter<MyViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val itemView = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_your_layout, parent, false)
        val holder = MyViewHolder(itemView)
        // 绑定焦点监听
        itemView.setOnFocusChangeListener { view, hasFocus ->
            val pos = holder.adapterPosition
            if (pos != RecyclerView.NO_POSITION) {
                focusListener.onItemFocusChanged(pos, hasFocus, view)
            }
        }
        return holder
    }
    // 剩余Adapter逻辑省略
}
  1. 在Activity/Fragment中实现接口即可统一处理所有条目焦点逻辑。

常见问题排查

如果焦点监听器未触发,可按以下顺序排查:

  • 确认条目根布局的focusable和focusableInTouchMode属性均设置为true
  • 确认RecyclerView本身未设置android:focusable="true",否则焦点会被RecyclerView本身拦截,不会下发到子条目
  • 若条目内部存在可聚焦控件,可将子控件的focusable属性设为false,或给条目根布局设置android:descendantFocusability="beforeDescendants"属性,确保根布局优先获得焦点

内容的提问来源于stack exchange,提问作者Harry Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 16:54:08