繁体   English   中英

回收站视图中每个项目的不同项目视图

[英]Different item view for each item in a Recycler View

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

getItemViewType(int position)

createViewHolder(ViewGroup parent, int viewType)

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

我最初的计划是在Recycler View Adapter中动态创建每个项目视图

onBindViewHolder(ViewHolder viewHolder, int i)

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

我现在的问题是

  1. 它仍然没有我想要的那么顺利。 如果您有任何解决方案或想法,我可以更快或更正确地做到这一点。 让我知道。

以下是回收站视图的三种可能不同视图的示例图像。 所以这些视图只包括照片和形状。 但其他观点包括文字和颜色。

在recyclerview中目前有3个不同的视图

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

我们实际上可以简化这个

我有最多8个图像和4个文本的视图,可以有不同的风格和位置。

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

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

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

还有一件事。

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

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

  1. 文本(最多2)id:0
  2. 文本(最多4个)id:1

这就是我将如何“命名”类型

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

总类型数实际上是

int type_count = (4 * 2) = 8

结束适配器的“基础”是这样的

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
}

因为我不知道你能得到什么作为你的元素的“数据”不能帮助你在这里。 因此在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上,使它更具负责性),你不关心它们实际上是如何加载的,什么时候,添加占位符很容易,缓存在内存和缓存中in for disk允许更快的加载时间。

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

干杯。

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

    List<List<image>> list 

2将它传递给你的适配器

3.在getItemView方法中使用if根据设置类型

    list.get(position).size();

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM