【问题标题】:Multiple RecyclerViews in ScrollView not Scrolling all the WayScrollView 中的多个 RecyclerViews 不能一直滚动
【发布时间】:2019-09-12 01:14:42
【问题描述】:

我有三个水平滚动回收器视图,对于应用程序屏幕来说,它们在垂直方向上太大了。为了解决这个问题,我将它们嵌套在 NestedScrollView 中,但是垂直滚动不会一直到最后一个回收器视图的底部。

这是视图将滚动的最远:

这是我的配置:

容器视图:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fillViewport="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <include
                android:id="@+id/recyclerTop"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                layout="@layout/recycler_with_filters"/>

            <include
                android:id="@+id/recyclerMiddle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                layout="@layout/recycler_with_filters"/>

            <include
                android:id="@+id/recyclerBottom"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                layout="@layout/recycler_with_filters"/>

        </LinearLayout>

    </androidx.core.widget.NestedScrollView>

</LinearLayout>

包含的布局:

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/header"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:text="Test!"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="24sp"
        app:fontFamily="@font/didot"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/filters"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:orientation="horizontal"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/header">

        <Button
            android:id="@+id/filter1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/btn_filter_inactive"
            android:textColor="@color/colorPrimaryDark"
            android:text="filter1" />

        <Button
            android:id="@+id/filter2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/btn_filter_inactive"
            android:textColor="@color/colorPrimaryDark"
            android:text="filter2" />

        <Button
            android:id="@+id/filter3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/btn_filter_inactive"
            android:textColor="@color/colorPrimaryDark"
            android:text="filter3" />

        <Button
            android:id="@+id/filter4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/btn_filter_inactive"
            android:textColor="@color/colorPrimaryDark"
            android:text="filter4" />

    </LinearLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:scrollbars="vertical"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/filters" />

</androidx.constraintlayout.widget.ConstraintLayout>

控制器:

公共类 TestRecyclerFragment 扩展片段 {

public static TestRecyclerFragment newInstance() {
    return new TestRecyclerFragment();
}

private RecyclerView mRecyclerViewTop;
private RecyclerView mRecyclerViewMiddle;
private RecyclerView mRecyclerViewBottom;
private RecyclerView.Adapter mAdapterTop;
private RecyclerView.Adapter mAdapterMiddle;
private RecyclerView.Adapter mAdapterBottom;


private Business[] mBusinesses = {new Business("The Tavern", 0), new Business("The Tavern1", 0), new Business("The Tavern2", 0), new Business("The Tavern3", 0), new Business("The Tavern4", 0), new Business("The Tavern5", 0), new Business("The Tavern6", 1), new Business("The Tavern7", 1), new Business("The Tavern8", 1), new Business("The Tavern9", 1), new Business("The Tavern10", 1), new Business("The Tavern11", 1)};

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.fragment_test_recycler, container, false);

    View recycleWithFilterTop = v.findViewById(R.id.recyclerTop);
    mRecyclerViewTop = recycleWithFilterTop.findViewById(R.id.recycler_view);

    View recycleWithFilterMiddle = v.findViewById(R.id.recyclerMiddle); 
    mRecyclerViewMiddle = recycleWithFilterMiddle.findViewById(R.id.recycler_view);

    View recycleWithFilterBottom = v.findViewById(R.id.recyclerBottom); 
    mRecyclerViewBottom = recycleWithFilterBottom.findViewById(R.id.recycler_view); 

    mRecyclerViewTop.setHasFixedSize(true);
    mRecyclerViewMiddle.setHasFixedSize(true);
    mRecyclerViewBottom.setHasFixedSize(true);

    RecyclerView.LayoutManager layoutManagerTop = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
    mRecyclerViewTop.setLayoutManager(layoutManagerTop);

    RecyclerView.LayoutManager layoutManagerMiddle = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
    mRecyclerViewMiddle.setLayoutManager(layoutManagerMiddle);

    RecyclerView.LayoutManager layoutManagerBottom = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
    mRecyclerViewBottom.setLayoutManager(layoutManagerBottom);

    mAdapterTop = new TestRecyclerFragment.TestAdapter(mBusinesses);
    mRecyclerViewTop.setAdapter(mAdapterTop);

    mAdapterMiddle = new TestRecyclerFragment.TestAdapter(mBusinesses);
    mRecyclerViewMiddle.setAdapter(mAdapterMiddle);

    mAdapterBottom = new TestRecyclerFragment.TestAdapter(mBusinesses);
    mRecyclerViewBottom.setAdapter(mAdapterBottom);

    return v;
}

public class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder> {
    private Business[] businesses;

    public class MyViewHolder extends RecyclerView.ViewHolder {
        private TextView mBusinessName;

        public MyViewHolder(View v) {
            super(v);
            mBusinessName = itemView.findViewById(R.id.businessName);
        }
    }

    public TestAdapter(Business[] myDataset) {
        mBusinesses = myDataset;
    }

    @Override
    public TestAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
                                                       int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.view_holder_businesses, parent, false);

        MyViewHolder vh = new MyViewHolder(v);
        return vh;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.mBusinessName.setText(mBusinesses[position].getName());
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mBusinesses.length;
    }

    @Override
    public int getItemViewType(int position) {
        return mBusinesses[position].getViewType();
    }
}

}

*编辑:我认为问题与滚动有关,不知道在绘制视图时视图将有多大。我已经尝试像这样对包含中的高度进行硬编码:

<include
    android:id="@+id/recyclerTop"
    android:layout_width="match_parent"
    android:layout_height="400dp"
    layout="@layout/recycler_with_filters"/>

但是这会破坏视图。

*Edit2:我已经尝试了许多在有关此主题的其他问题中提倡的解决方案,包括将设置 nestedScrollingEnabling 设置为 false。这些解决方案在我的实例中不起作用。我不确定这是我的配置不同还是我使用的是较新版本的 NestedScrollView api。

【问题讨论】:

  • 我已经测试了你的代码,它在我这边工作得很好,你能发布 view_holder_businesses 布局文件吗
  • @Barden Holt 我也面临同样的问题。你找到解决办法了吗?
  • @ShubhamAnand 检查我在下面关于向布局参数添加动态高度的答案。如果这不起作用,请发布一些代码,我可以看看!

标签: android android-recyclerview


【解决方案1】:

考虑到市场上不同的屏幕分辨率,添加静态高度并不是一个合适的解决方案。如果你想在NestedScrollView 内有多个Recyclerviews 作为一个整体滚动,你应该考虑将android:nestedScrollingEnabled="false" 添加到Recyclerview

<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="@dimen/margin_activity_horizontal">

        <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layoutManager="LinearLayoutManager"
            android:nestedScrollingEnabled="false"/>

        <android.support.v7.widget.RecyclerView
            android:layout_below="@+id/recycler_view_departments"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layoutManager="LinearLayoutManager"
            android:nestedScrollingEnabled="false"/>

    </RelativeLayout>
</android.support.v4.widget.NestedScrollView>

【讨论】:

  • 我同意我的解决方案不是最理想的,但将 nestedScrollingEnabled 设置为 false 不会影响滚动位置。有很多解决方案提倡您的方法,所以我不确定它是否与较新版本的 api(我正在使用 androidx.core.widget.NestedScrollView)或我的配置有关,但它不起作用.
  • 我刚刚添加了一些 dp 到像素的转换代码,使我的解决方案更加动态。它似乎在多种屏幕尺寸上都能正常工作。
【解决方案2】:

我已经测试了你的代码,它在我这边运行良好,只是我在 TestRecyclerFragment onCreateView 方法中添加了以下 3 行代码

    mRecyclerViewTop.setNestedScrollingEnabled(false);
    mRecyclerViewMiddle.setNestedScrollingEnabled(false);
    mRecyclerViewBottom.setNestedScrollingEnabled(false);

你可以看到工作演示https://www.dropbox.com/s/zmfmcdjw58cto4q/device-2019-09-05-115921.mp4?dl=0

【讨论】:

    【解决方案3】:

    通过向底部回收器视图的布局参数添加动态高度,我能够让滚动视图滚动到底部:

    RecyclerView.LayoutManager layoutManagerBottom = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
    mRecyclerViewBottom.setLayoutManager(layoutManagerBottom);
    
    final float scale = getContext().getResources().getDisplayMetrics().density;
    int pixels = (int) (550 * scale + 0.5f);
    mRecyclerViewBottom.getLayoutParams().height = pixels;
    

    【讨论】:

    • 这里的 550 是什么?那是 1 listItem 的高度吗?
    • @ShubhamAnand 是的。这是一个老生常谈的答案,我可能在某个时候有所改进。但它可能会让你走上正轨。
    • 您的解决方案似乎有效。谢谢。 @BradenHolt
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多