美文网首页android开发知识
Android TV--RecyclerView中item焦点实

Android TV--RecyclerView中item焦点实

作者: Jack_Jiao | 来源:发表于2020-09-30 11:21 被阅读0次

    我们在开发android tv应用时需要使用遥控器来控制RecyclerView的焦点,来向用户展示当前选中的是哪个item。不可避免的会涉及以下几个问题:

    • 设置item获得焦点时的效果
    • RecyclerView重新获得焦点后,选中上次的item
    • RecyclerView失去焦点后,继续保持item的选中效果

    下面对这三个问题逐个击破

    设置item获得焦点时的效果

    先上效果图

    获得焦点.gif

    只需要按下面这样设置item布局即可,

    • 使用selector设置背景
    • 设置clickablefocusabletrue
    <!--item.xml-->
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="@drawable/item_selector"
            android:clickable="true"
            android:focusable="true">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{item}"
                android:textColor="@android:color/white"
                android:textSize="24sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
    
        </androidx.constraintlayout.widget.ConstraintLayout>
    

    item_selector.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@color/select_bg_color" android:state_selected="true" />
        <item android:drawable="@color/select_bg_color" android:state_focused="true" />
        <item android:drawable="@android:color/darker_gray" />
    </selector>
    

    重新获得焦点后,选中上次的item

    先上效果图

    选中上次位置.gif

    上面的效果,我们使用Leanback库中的VerticalGridView即可实现。

    因为VerticalGridView extends BaseGridView extends RecyclerView,所以之前使用RecyclerView的代码基本不用改变,并且不用调用setLayoutManager

    依赖

    implementation "androidx.leanback:leanback:1.0.0"

    使用

    <androidx.leanback.widget.VerticalGridView
            android:id="@+id/vertical_gridview"
            android:layout_width="100dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    

    失去焦点后,继续保持item的选中效果

    先上效果图

    保持选中效果.gif

    当焦点在item中切换时,

    • item0item1item0失去焦点,item1获得焦点

    • item1item2item1失去焦点,item2获得焦点

    如果此时,焦点从RecyclerView切换到其他控件,item2失去焦点。

    所以我们记录获得焦点和失去焦点的item,如果获得焦点和失去焦点的是同一个item,那么就表示RecyclerView失去了焦点,我们需要设置这个item为选中效果。

    class MainAdapter() : ListAdapter<String, RecyclerView.ViewHolder>(MainDiffCallback()) {
    
        /** 记录获得焦点和失去焦点的item */
        private val map = mutableMapOf<Boolean, String>()
        private var lastSelectedView: View? = null
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
            return MainViewHolder(
                    ItemBinding.inflate(
                            LayoutInflater.from(parent.context),
                            parent,
                            false
                    )
            )
        }
    
        override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
            val item = getItem(position)
            with(holder as MainViewHolder) {
                itemView.tag = item
                bind(item)
            }
        }
    
        inner class MainViewHolder(private val binding: ItemBinding) : RecyclerView.ViewHolder(binding.root) {
            init {
                binding.root.setOnFocusChangeListener { view, hasFocus ->
                    map[hasFocus] = view.tag as String
                    if (map[true] == map[false]) {
                        // 获得焦点和失去焦点的是同一个item,会有以下两种情况:
                        //  RecyclerView失去焦点
                        //  RecyclerView重新获得焦点
                        // 让此item保持选中状态,
                        view.isSelected = true
                        lastSelectedView = view
                    } else {
                        lastSelectedView?.isSelected = false
                    }
                }
            }
    
    
            fun bind(item: String) {
                binding.apply {
                    this.item = item
                    executePendingBindings()
                }
            }
        }
    }
    

    完整demo

    TvRecyclerViewDemo in github

    相关文章

      网友评论

        本文标题:Android TV--RecyclerView中item焦点实

        本文链接:https://www.haomeiwen.com/subject/lseuuktx.html