回收站视图中

时间:2015-09-30 13:49:05

标签: android android-recyclerview

我正在尝试构建一个水平回收站视图,每个项目都是相同的父类型,但最多可以包含十个不同的子视图。我查看了this answer,其中解释了如何覆盖

getItemViewType(int position)

createViewHolder(ViewGroup parent, int viewType)

但这只适用于每个项目的观看次数有限的情况。我必须显示的项目列表大小为40,每个项目最多可包含8个图像,每个图像位于父视图的不同位置。

我最初的计划是在

中的Recycler View Adapter中动态创建每个项目视图
onBindViewHolder(ViewHolder viewHolder, int i)

这导致了问题,因为每次看到该项目时,我都必须创建所有单独的视图并将它们附加到父视图。那么我在活动中创建了一个视图列表,其中包含了Recycler视图,而不是传入对象列表来创建视图,我只是传递了视图本身。由于我每次都不必阅读每个项目并且每次加载时都为每个项目创建自定义视图,因此效果更好。

我现在的问题是

  1. 它仍然没有我想要的那么顺利。如果您有任何解决方案或想法,我可以更快或更正确地做到这一点。让我知道。
  2. 以下是回收者视图的三种可能不同视图的示例图像。所以这些视图只包括照片和形状。但其他观点包括文字和颜色。

    Current 3 different views in recyclerview

2 个答案:

答案 0 :(得分:3)

  

每个项目视图最多可选择8个图像,边框或没有边框>这些图像,最多4个文本框,条纹,实线,无边框,剪贴画>以及不同颜色的选项每一个查看项目。每个项目上还有不同的>尺寸和不同的位置。物品的外观几乎是无穷无尽的

我们实际上可以将其简化为

  

我有最多8张图片和4张文字,可以有不同的视图   风格和位置。

然后,只有45种可能性来挑选将有多少图像和文本(计算没有图像或文本的可能性)。

因此,如果我使用enought元素创建简单的RelativeLayout,然后根据需要移动它们......

Hovewer说45种可能的类型很好...... 方式太多了。你看到制作任何适配器都带有太多的项目类型并不是很聪明,简单地说,当为适配器视图(或ListView)设置适配器时,首先要做的就是创建" small" ViewPool(RecyclerViewPool),它基本上是simple sparse array,它将保留任何被删除的ViewHolder,直到它被重用的时间到来,如果堆太大,它将被删除。这就是理论,在实践中,在特定时间有多少scap孩子是有限的(对于我认为约为5的回收者),所以如果我们要创建具有多种类型的视图持有者,我们希望在大多数时间点击缓存,因为我们的类型没有废料视图持有者,所以会调用createViewHolder,实际上这会更像我们根本没有视图持有者。

还有一件事。

  

然后我在活动中创建了一个视图列表,其中包含了回收器视图>而不是传入对象列表来创建视图,我只是>传递视图本身。由于我从未必须每次都阅读每个项目并且每加载一次>时间为每个项目创建自定义视图,因此效果更好。

Recycler视图用于卸载不再需要的项目(视图),或者我应该说用户不可见,还可以尽可能地重新使用旧视图以减少布局膨胀次数和搜索次数为了id。 通过随时加载它们,可以省略此功能。

如果我没有弄错,这可能比使用LinearLayout(Vertical)创建ScrollView并将所有视图放入其中要慢一些。 Hovewer最大的缺点是你的所有视图都是随时加载的,如果它们很简单,我真的不明白为什么不使用ScrollView + LinearLayout,但如果不好,这会变得复杂,在新手机上,内存不是那么大的问题,有500+ mb的手机,但即便如此,并不是每部手机都能为你的应用提供300 MB的功率。

我的回答

我猜它想成为你想听到的东西:)

减缓布局膨胀的事情,实际上并没有设置文本,背景或位置,而是加载资源来执行此操作,并搜索视图。

让我们开始: 使用缓存为您加载的资源尽可能地重用它们(我在最后添加了关于图像加载的小部分)。 FindViewById真的很慢,我的意思是,只需使用视图模式并删除搜索视图就可以获得很好的加速。

您希望远离设置每个元素的布局。

想法非常简单,根据主要层次结构的数量创建布局组视图(此时)图像和文本。在创建ViewHolder时创建RelativeLayout,推送足够的图像/文本以满足您对位置元素的需求。绑定数据时会根据需要移动元素并设置样式。

要减少类型数量,请使用舍入为2的图像/文本数。

更新LayoutParams并不像我们想象的那样花费太多,它花费了一些,不要误会我的意思,这基本上迫使父母进行额外的子测量和布局更新,这就是全部,而视图将被显示,它必须无论如何都要进行这种测量和布局更新:)

让我们说我们有这两个小组

  1. 图片(最多2个)id:0
  2. 图片(最多4个)id:1
  3. 图片(最多6个)id:2
  4. 图片(最多8个)id:3
  5. 并且

    1. 文字(最多2)id:0
    2. 文字(最多4)id:1
    3. 这就是我将如何"命名"类型

      int type = (img_id)<<1 | (txt_id) 
      

      总类型数实际上是

      int type_count = (4 * 2) = 8
      

      结束我们的&#34;基地&#34;适配器是这样的

      public class MyAdapter<MyType extends MyAdapter.MyTypeBase> extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
      Context context;
      ArrayList<MyType> elements;
      
      public MyAdapter(Context context, ArrayList<MyType> elements) {
          this.context = context;
          this.elements = elements;
      }
      
      public int getItemCount() { return elements.size(); }
      public MyType get(int position) { return elements.get(position); }
      
      public int getItemViewType(int position) {
          int imgs = get(position).getImageCount();
          int txts = get(position).getTextCount();
          imgs = (imgs/2) * 2 + (imgs % 2 == 0 ? 0 : 1);
          txts = (txts/2) * 2 + (txts % 2 == 0 ? 0 : 1);
          return imgs << 1 | txts;
      }
      
      @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
          return new ViewHolder(new RelativeLayout(context), position); // or use inflater to inflate some base layout
      }
      
      
      class ViewHolder extends RecyclerView.ViewHolder {
          int textCount, imageCount;
          RelativeLayout root;
          ImageView [] imageViews;
          TextView [] textViews;
          public ViewHolder(RelativeLayout view, int position) {
              super(view);
              root = view;
              textCount = (position & 1) * 2;
              imageCount = (position >> 1) * 2;
              textViews = new TextView[textCount];
              imageViews = new ImageView[imageCount];
              for (int i = 0; i < imageCount; i++) {
                  root.addView(imageViews[i] = new ImageView(context)); // or use inflater
              }
              for (int i = 0; i < textCount; i++) {
                  root.addView(textViews[i] = new TextView(context)); // or use inflater
              }
          }
      }
      
      interface MyTypeBase {
          int getImageCount();
          int getTextCount();
      }
      

      并且缺少某些东西:)

      public void onBindViewHolder(ViewHolder viewHolder, int position) {
          MyTypeBase element = get(position);
          vh.textViews[vh.textCount-1].setVisibility(element.getTextCount()%2 == 0? View.VISIBLE : View.GONE);
          vh.imageViews[vh.imageCount-1].setVisibility(element.getImageCount()%2 == 0? View.VISIBLE : View.GONE);
      
          // now this is your place to shine
      }
      

      因为我不知道你能得到什么&#34;数据&#34;因为你的元素在这里无法帮助你。所以在bindViewHolder中,viewHolder将根据你的元素需要提供足够的图像和文本,重新加载任何图像并移动它们。

      最后的注释

      我还应该在这里和那里添加fev笔记:)

      懒惰。是的我的意思是当你想要懒惰的时候,你试着让你的解决方案尽可能简单,使代码更容易阅读,并且不太可能有重大错误:)

      另外请使用库来显示和缓存图像,而不是每次都加载它们。很少有像UniwersalImageLoader,Picasso或Volley这样的好人。我个人使用UIL这样的例子。

      // This might be done in helper class ^^
      DisplayImageOptions OPTIONS_DISC_AND_CACHE = new DisplayImageOptions.Builder()
                      .cacheOnDisk(true)
                      .cacheInMemory(true)
                      .build();
      
      ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(context)
      //              .memoryCacheSize((int) (Runtime.getRuntime().maxMemory() / 1024) / 16) // if you want to reduce it some more ^^
                      .threadPoolSize(4)
                      .tasksProcessingOrder(QueueProcessingType.LIFO)
                      .build();
      
              imageLoader.init(configuration);
      
      // And thats how to use it
      ImageLoader.getInstance().displayImage("MY URL", (ImageView) myImageView, Tools.OPTIONS_DISC_AND_CACHE);
      

      为什么你应该使用这样的库,dunno ...图像是异步加载的(不是在ui上,使它更具可取之处),你不关心它们实际上是如何加载的,何时添加占位符很容易,缓存在磁盘中的内存和缓存可以加快加载速度。

      最后,英语不是我的主要语言,所以如果我拼写错误,忘记逗号,或以错误的方式写句子,请做更正。

      干杯。

答案 1 :(得分:0)

1创建列表列表,每个项目应包含1个或多个图像

    List<List<image>> list 

2将它传递给你的适配器

getItemView方法中的

3使用if根据

设置类型
    list.get(position).size();

4再次使用if或isinstanceof或者我认为viewHolder有一个方法来获取它的类并将你的viewHolder转换为正确的类。