如何在Android TV上实现RecyclerView的滚动?

9

我有一个应用程序,需要为Android TV进行适配。这个应用程序包含水平的RecyclerView,在使用遥控器D-pad按钮时无法滚动。 我找到了这个解决方案,但是它会导致崩溃。 以下是代码:

<ru.myapp.package.HorizontalPersistentFocusWrapper
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
       <android.support.v7.widget.RecyclerView
           android:id="@+id/recycler_view"
           android:layout_width="match_parent"
           android:layout_height="250dp"
           android:background="@null"
           android:scrollbars="none"/>
</ru.myapp.package.HorizontalPersistentFocusWrapper>

HorizontalPersistentFocusWrapper与PersistentFocusWrapper相同,但mPersistFocusVertical = false;

崩溃发生在这个地方:

@Override
    public void requestChildFocus(View child, View focused) {
        super.requestChildFocus(child, focused);
        View view = focused;
        while (view != null && view.getParent() != child) {
            view = (View) view.getParent(); <<<------ Crash here
        }
        mSelectedPosition = view == null ? -1 : ((ViewGroup) child).indexOfChild(view);
        if (DEBUG) Log.v(TAG, "requestChildFocus focused " + focused + " mSelectedPosition " + mSelectedPosition);
    }

崩溃堆栈:

java.lang.ClassCastException: android.view.ViewRootImpl cannot be cast to android.view.View
         at ru.myapp.package.HorizontalPersistentFocusWrapper.requestChildFocus(HorizontalPersistentFocusWrapper.java:108)
         at android.view.View.handleFocusGainInternal(View.java:5465)
         at android.view.ViewGroup.handleFocusGainInternal(ViewGroup.java:714)
         at android.view.View.requestFocusNoSearch(View.java:8470)
         at android.view.View.requestFocus(View.java:8449)
         at android.view.ViewGroup.requestFocus(ViewGroup.java:2747)
         at android.view.View.requestFocus(View.java:8416)
         at android.support.v4.widget.NestedScrollView.arrowScroll(NestedScrollView.java:1222)
         at android.support.v4.widget.NestedScrollView.executeKeyEvent(NestedScrollView.java:551)
         at android.support.v4.widget.NestedScrollView.dispatchKeyEvent(NestedScrollView.java:512)
         at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
         at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
3个回答

10
请使用最新版本的RecyclerView。或者至少使用<\br>com.android.support:recyclerview-v7:23.2.0<\br> 有关更多信息,请参见此链接:<\br>https://code.google.com/p/android/issues/detail?id=190526&thanks=190526&ts=1445108573<\br> 现在是重要部分:<\br> RecyclerView的新版本开始遵守其子项的规则(如高度和宽度)。 您必须在子项XML中设置根视图:<\br>android:focusable="true"<\br> 现在,滚动将按预期进行。

2
在recyclerview项的根视图中将focusable设置为true。 android:focusable="true"并在根视图项上应用一个选择器背景。所有这些都可以在xml文件中完成。通过以下设置,dpad或遥控器将能够向上和向下滚动列表,并且列表中当前选定的项将被突出显示。
RecyclerView中列表项的根视图的布局文件:list_item.xml,关键部分是android:background="@drawable/item_selector"android:focusable="true"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/item_selector"
    android:focusable="true">
    <TextView
        android:id="@+id/topic"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:textColor="#ffffff"
        android:gravity="center"
        tools:text="Education"/>
</LinearLayout>

在drawable文件夹中的可绘制选择器文件:item_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#000000" android:state_pressed="true"/>
<item android:drawable="#000000" android:state_selected="true"/>
<item android:drawable="#000000" android:state_focused="true"/>
<item android:drawable="#03A9F4"></item>
</selector>

包含RecyclerView的布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                             xmlns:tools="http://schemas.android.com/tools"
                                             android:layout_width="match_parent"
                                             android:layout_height="match_parent"
                                             xmlns:app="http://schemas.android.com/apk/res-auto"
                                             tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="none"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>

</android.support.constraint.ConstraintLayout>

1
尝试这个。对我有效。
    @Override
public void requestChildFocus(View child, View focused) {
    super.requestChildFocus(child, focused);
    View view = focused;
    while (view != null && view.getParent() != child) {
        try {
            view = (View) view.getParent();
        } catch (ClassCastException e) {
            view = null;
        }
    }
    mSelectedPosition = view == null ? -1 : ((ViewGroup) child).indexOfChild(view);
    if (DEBUG)
        Log.v(TAG, "requestChildFocus focused " + focused + " mSelectedPosition " + mSelectedPosition);
}

感谢您的回答。使用这段代码后,崩溃问题已经解决了。但是RecyclerView没有对d-pad做出反应。 - BArtWell
1
只是为了确保。HorizontalPersistentFocusWrapper 用于将 RecyclerView(s) 与垂直 LinearLayout 管理器和可能的其他视图包装在一起。要使用水平 LineaLayoutManagers 包装 RecyclerViews,请使用 VerticalPersistentFocusWrapper。 - Євген Гарастович

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接