【问题标题】:How to implement multiple recyclerviews in one layout?如何在一个布局中实现多个recyclerviews?
【发布时间】:2018-11-15 06:56:17
【问题描述】:

我想创建一个窗格,其中有两个RecyclerViews(比如说“MyItems”、“AllItems”)。我创建了垂直的LinearLayout,其中有TextView 作为标题和RecyclerView。像这样的:

 <LinearLayout ... >

    <TextView
        android:text="My Items"
        ... />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_items"
        ... />

    <TextView
        android:text="All Items"
        ... />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/all_items"
        ... />

</LinearLayout>

但是,使用这种方法,只有 recyclerViews 可以独立滚动,但我需要整个布局只能滚动(所以首先它滚动通过第一部分,然后是第二部分)。我试图用ScrollViewNestedScrollView 把它包起来,但我得到的最接近的是滚动没有流畅的动画

我的问题是,这种方法是否有效,如果有效,有没有办法在NestedScrollView 中添加平滑滚动?或者我应该使用另一种方法来实现它,例如创建包含两个项目的ListView,其布局包含TextViewRecyclerView

ListView

  • 列表项 1

    • 标题 1
    • RecyclerView 1
  • 列出项目 2

    • 标题2
    • RecyclerView2

我认为从性能方面来看,这种方法并不好。我对吗?我只需要为此找到最佳实践。谢谢。

【问题讨论】:

    标签: android performance android-recyclerview slidingpanelayout


    【解决方案1】:

    请不要使用嵌套滚动。它将破坏回收器视图的目的,并将所有内容保留在内存中,因为两个回收器的高度都将设置为最大值。 而是继续以下两个选择:

    1.如果您没有特定背景,请创建一个带有适配器的单个 RecyclerView,类似于以下内容:

    public class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    
        ArrayList<Integer> data = new ArrayList<>();
        private final int VIEW_TYPE_TEXTVIEW = 0;
        private final int VIEW_TYPE_ITEM_1 = 1;
        private final int VIEW_TYPE_ITEM_2 = 2;
        private final LayoutInflater inflater;
        private final ArrayList<Integer> data;
    
        public MyRecyclerAdapter(Context ctx, ArrayList<Integer> data){
            this.context = ctx;
            this.data = data;
            inflater = LayoutInflater.from(context);
        }
    
        @Override
        public int getItemViewType(int position) {
            return data.get(position);
        }
    
        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            if(viewType == VIEW_TYPE_TEXTVIEW){
                View view = inflater.inflate(R.layout.simple_textview, parent, false);
                return new TextViewHolder(view);
            }else if(viewType == VIEW_TYPE_ITEM_1){
                View view = inflater.inflate(R.layout.item_top_recycler, parent, false);
                return new Item1Holder(view);
            }else{
                View view = inflater.inflate(R.layout.item_bottom_recycler, parent, false);
                return new Item2Holder(view);
            }
        }
    
        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            if(holder instanceof TextViewHolder){
                ((TextViewHolder) holder).textView.setText(...);
            }else if(holder instanceof Item1Holder){
                ((Item1Holder) holder).itemTextView.setText(...);
            }else if(holder instanceof Item2Holder){
                ((Item2Holder) holder).itemTextView.setText(...);
            }
        }
    
        @Override
        public int getItemCount() {
            return data.size();
        }
    
        class TextViewHolder extends RecyclerView.ViewHolder {
    
    
            TextView textView;
    
            public HeaderHolder(View itemView) {
                super(itemView);
                textView = itemView.findViewById(R.id.tv);
            }
        }
        class Item1Holder extends RecyclerView.ViewHolder {
    
    
            TextView itemTextView;
    
            public HeaderHolder(View itemView) {
                super(itemView);
                itemTextView = itemView.findViewById(R.id.tv);
            }
        }
        class Item2Holder extends RecyclerView.ViewHolder {
    
    
            TextView itemTextView;
    
            public HeaderHolder(View itemView) {
                super(itemView);
                itemTextView = itemView.findViewById(R.id.tv);
            }
        }
    }
    

    然后像下面这样设置你的适配器:

    ArrayList<Integer> data = new ArrayList<>();
    //Adding first textview
    data.add(0);
    //Adding 10 elements of first RecyclerView
    for(int i = 0; i<10; i++){
        data.add(1);
    }
    //Adding second textview
    data.add(0);
    //Adding 10 elements of second RecyclerView
    for(int i = 0; i<10; i++){
        data.add(2);
    }
    
    adapter = new MyRecyclerAdapter(this, data);
    navView.setAdapter(adapter);
    

    这样,您也可以使用 RecyclerView 来包含您的 textview。这种方法会给你最好的优化。确保在 getItemViewType() 中为上层 recyclerView、下层 RecyclerView 和 TextViews 返回适当的 VIEW_TYPE。

    第二种方法是让一个 RecyclerView 包含 4 个项目:

    • 文本视图
    • 线性布局
    • 文本视图
    • 线性布局

    然后用项目动态填充这些线性布局。这将确保至少有一个 Linearlayout 在看不见时被回收。即便如此,第一种方法也会比这更好。

    【讨论】:

    • 谢谢你的好例子。但是,您能解释一下,onCreateViewHolder 是如何知道正确的 viewType 的吗?你在哪里设置的?
    • 您可以修改getItemViewType()。现在,它返回我在创建适配器对象时输入的数字。如果它有一个0,该项目将被视为一个textview,如果数字为1,则为上recyclerview的项目,2为下recyclerview的项目。
    • 如果这对你有用,你能接受我的回答正确吗?
    【解决方案2】:

    首先,除非有充分的理由,否则在一个屏幕中显示两个回收站视图并不是一个好主意。尝试在一个回收站视图中使用带有标题的不同部分。

    如果还想用,在NestedScrollView中嵌入布局,并将recyclerView的nestedScrollingEnabled属性设置为false

    recyclerView.setNestedScrollingEnabled(false);
    

    提示:查看FastAdapter,这会使工作更轻松。

    【讨论】:

    • 之后我需要显示“我的项目”和“所有项目”。也许还会有一个“节”。如何使用一个 recyclerView 来完成?只维护一个 RecyclerView 不会导致更复杂吗?
    • 维护多个部分的关键是 RecyclerView Adapter 的onCreateViewHolder(parent: ViewGroup, viewType: Int) 方法,您可以在其中决定它是什么类型的视图并相应地扩展视图。
    • 有很多库可以让这项工作比我们自己设置一切更容易。如果您想从头开始设置,请查看此post(或类似的)以获取更多详细信息。
    • Facebook、youtube、netflix 甚至 Play 商店等非常好的应用程序在相同的布局中使用两个或多个 RV(为了它们的外观)
    • 你指的是垂直滚动列表中的水平滚动列表吗?
    【解决方案3】:

    无论您要达到什么目的,最好按照以下链接所示完成: http://khmertechtrain.tk/index.php/2017/10/03/create-a-vertical-scroll-and-horizontal-scroll-app-like-google-play-store/

    此外,如果所有视图都相似,您将需要使用 RecycledViewPool 以便在多个 RecyclerView 之间共享视图。

    【讨论】:

      【解决方案4】:

      您应该尝试您所说的最接近您想要的 NestedScrollView 解决方案:

      NestedScrollView
         TextView
         RecyclerView
         TextView
         RecyclerView
      

      为了平滑滚动,您需要在回收站视图中设置一个属性:

       recyclerView.setNestedScrollingEnabled(false);
      

      这样您的布局将滚动 NestedScrollView 而不是 RV。

      【讨论】:

      • 不,只是不!这是一种可怕的做法,违背了 RecyclerView 的目的,因为它始终将所有视图保留在内存中,并且没有任何东西可以回收/释放内存参与。
      • 感谢您的评论 :)
      • 然而,没有必要对 tgis 反应过度
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-25
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多