Android TV 在 RecyclerViews 之间移动焦点

Posted

技术标签:

【中文标题】Android TV 在 RecyclerViews 之间移动焦点【英文标题】:Android TV move focus between RecyclerViews 【发布时间】:2016-05-14 05:32:16 【问题描述】:

我正在构建一个具有以下布局的 android TV 应用:

左右两个列表都是带有垂直 LinearLayoutManagers 的 RecyclerViews,Header 视图是静态的。使用 D-PAD 导航可以在一个列表中正常工作,但是从一个列表切换到另一个列表时会出现问题。焦点从列表 1 的第 5 项移动到列表 2 的第 5 项。当列表 2 少于 5 项时,它就会失去焦点。

我希望保存最后一个焦点项目索引,当用户导航 list1-list2-list1 时,具有该索引的项目再次获得焦点,并防止视图失去焦点。有什么好的解决办法吗?

要求的行为: 用户导航到列表顶部并按“UP” - 焦点停留在原处,没有任何反应。 用户导航到列表底部并按下“DOWN” - 焦点停留在原处,没有任何反应。 用户从 list1 导航到 list2 - 以前在 list2 中具有焦点的项目获得焦点,如果之前没有焦点,则 item0 获得焦点。

主要布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    >

    <ImageView
        android:id="@+id/iv_background"
        android:layout_
        android:layout_
        android:focusable="false"
        />

    <LinearLayout
        android:layout_
        android:layout_
        android:layout_marginBottom="27dp"
        android:layout_marginLeft="48dp"
        android:layout_marginRight="48dp"
        android:layout_marginTop="27dp"
        android:orientation="horizontal"
        >

        <LinearLayout
            android:layout_
            android:layout_
            android:layout_weight="2"
            android:orientation="vertical"
            >

            <LinearLayout
                android:layout_
                android:layout_
                android:focusable="false"
                android:orientation="horizontal"
                >

                <ImageView
                    android:id="@+id/iv_poster"
                    android:layout_
                    android:layout_
                    />

                <LinearLayout
                    android:layout_
                    android:layout_
                    android:layout_weight="1"
                    android:orientation="vertical"
                    >

                    <TextView
                        android:id="@+id/tv_title"
                        android:layout_
                        android:layout_
                        />

                    <FrameLayout
                        android:layout_
                        android:layout_
                        >

                        <TextView
                            android:id="@+id/tv_release_date"
                            android:layout_
                            android:layout_
                            android:layout_gravity="left"
                            />

                        <TextView
                            android:id="@+id/tv_rating"
                            android:layout_
                            android:layout_
                            android:layout_gravity="right"
                            android:drawableLeft="@drawable/ic_star_white_24dp"
                            android:drawablePadding="@dimen/view_padding_small"
                            />

                    </FrameLayout>

                    <TextView
                        android:id="@+id/tv_description"
                        android:layout_
                        android:layout_
                        android:layout_weight="1"
                        />
                </LinearLayout>

            </LinearLayout>

            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv_seasons_list"
                android:layout_
                android:layout_
                android:layout_weight="1"
                android:focusable="false"
                />

        </LinearLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_episodes_list"
            android:layout_
            android:layout_
            android:layout_weight="3"
            android:focusable="false"
            />

    </LinearLayout>

</FrameLayout>

项目布局,用于两个列表:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:orientation="horizontal"
    android:focusable="true"
    >

    <TextView
        android:id="@+id/tv_title"
        android:layout_
        android:layout_
        android:gravity="center_vertical"
        android:layout_weight="1"
        />

    <TextView
        android:id="@+id/tv_episodes_count"
        android:layout_
        android:layout_
        android:gravity="center_vertical"
        android:ems="10"
        />

</LinearLayout>

【问题讨论】:

你能发布你的xml文件吗? 所以你想在你的回收站视图之间移动焦点,你能解释一下吗? 正确。我想记住 recyclerviews 中的最后一个焦点位置。当用户从 list1 导航到 list2 并返回到 list1 时,我想恢复 list1 以前关注的项目。 list2 也是如此。我也希望当用户在 list1 中的 item1 聚焦时按下 d-pad 上的“向上”时焦点不会移动,依此类推 您是否尝试过任何代码来获取最后位置的焦点,如果没有,请查看此链接***.com/questions/26682277/… jaydroider,选择和关注是不同的东西。我可以得到最后一个焦点位置,但看不到恢复它的方法。 【参考方案1】:

通过 Google 的 Leanback 库资源挖掘回答了我的付款人。 如果你遇到同样的麻烦,只需用this 包装你的 RecyclerViews 并且不要忘记设置

private boolean mPersistFocusVertical = false;

如果您希望在水平搜索时保持焦点,例如在我的布局中。

【讨论】:

你是如何使用这个私人课程的?你能给出一个解决方案的示例代码,你的意思是把它包装在xml中吗? 复制代码即可。它与私有访问没有依赖关系。它对我有用。 链接不起作用 (404)。能否请您提供正确的链接? 它是来自 Google v17-leanback 库的 PersistentFocusWrapper 类。您可以搜索最新版本。现在可以在这里找到:android.googlesource.com/platform/frameworks/support/+/master/… @ЄвгенГарастович 你有没有遇到任何崩溃?我明白了:***.com/questions/39856750/…【参考方案2】:

如下修改你的主布局。

对于定向导航,我们可以添加 nextFocusDown、nextFocusLeft、nextFocusRight、nextFocusUp 等属性,以根据我们的要求聚焦相关项目。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
>

<ImageView
    android:id="@+id/iv_background"
    android:layout_
    android:layout_
    android:focusable="false"
    />

<LinearLayout
    android:layout_
    android:layout_
    android:layout_marginBottom="27dp"
    android:layout_marginLeft="48dp"
    android:layout_marginRight="48dp"
    android:layout_marginTop="27dp"
    android:orientation="horizontal"
    >

    <LinearLayout
        android:layout_
        android:layout_
        android:layout_weight="2"
        android:orientation="vertical"
        >

        <LinearLayout
            android:layout_
            android:layout_
            android:focusable="false"
            android:orientation="horizontal"
            >

            <ImageView
                android:id="@+id/iv_poster"
                android:layout_
                android:layout_
                />

            <LinearLayout
                android:layout_
                android:layout_
                android:layout_weight="1"
                android:orientation="vertical"
                >

                <TextView
                    android:id="@+id/tv_title"
                    android:layout_
                    android:layout_
                    />

                <FrameLayout
                    android:layout_
                    android:layout_
                    >

                    <TextView
                        android:id="@+id/tv_release_date"
                        android:layout_
                        android:layout_
                        android:layout_gravity="left"
                        />

                    <TextView
                        android:id="@+id/tv_rating"
                        android:layout_
                        android:layout_
                        android:layout_gravity="right"
                        android:drawableLeft="@drawable/ic_star_white_24dp"
                        android:drawablePadding="@dimen/view_padding_small"
                        />

                </FrameLayout>

                <TextView
                    android:id="@+id/tv_description"
                    android:layout_
                    android:layout_
                    android:layout_weight="1"
                    />
            </LinearLayout>

        </LinearLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_seasons_list"
            android:layout_
            android:layout_
            android:layout_weight="1"
            android:focusable="false"
            android:nextFocusDown="@+id/rv_episodes_list"
            />

    </LinearLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_episodes_list"
        android:layout_
        android:layout_
        android:layout_weight="3"
        android:focusable="false"
        android:nextFocusUp="@+id/rv_seasons_list"
        />

</LinearLayout>

希望这能解决你的问题!!

【讨论】:

感谢您的想法,但这无济于事。如果它到达列表的顶部/底部,我需要保持焦点。而且它根本不影响向左/向右移动焦点。 将您的应用的屏幕截图与您拥有的相关行放在一起。 我已经使用你的代码在这里创建了一个小测试项目jgarin@bitbucket.org/jgarin/tv-test.git 当你按住 d-pad 的上/下焦点从一个列表移动到另一个列表时,以前的焦点位置没有保存/恢复 尝试获取列表 1 的最后一个焦点位置并存储在共享首选项中。 获取和存储不是问题,我可以处理。但恢复焦点是。有什么想法吗?

以上是关于Android TV 在 RecyclerViews 之间移动焦点的主要内容,如果未能解决你的问题,请参考以下文章

焦点更改时强制 RecyclerView 滚动(Android TV)

android tv常见问题(四)焦点变化时,Recyclerview是如何进行滚动的

潜在的 Glide 错误 - 在 Android TV 上使用 Dpad 快速滚动时,RecyclerView 项目失去焦点

Android Tv RecyclerView 设置其项目的下一个焦点

Android为TV端助力 listview与recyclerview上下联动

Android TV端的(RecyclerView)水平滚动焦点错乱问题