在RecyclerView项目中显示动态数量的视图?

时间:2017-03-29 18:21:47

标签: android android-layout android-recyclerview

我正在尝试重新创建:

enter image description here

我有一个数据列表:

List<Block> blocks;

Block.java类有一个方法getNumBlocks(),它返回该项应显示的块数。块的数量范围可以从小到1块到大到20块。

我创建了一个普通的RecyclerView适配器,以及块的ImageView布局:

public class BlockAdapter extends RecyclerView.Adapter<BlockAdapter.ViewHolder> {

    private Context context;

    private List<Block> blocks;

    public BlockAdapter(Context context, List<Block> blocks) {
        this.context = context;
        this.blocks = blocks;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView block;

        public ViewHolder(View v) {
            super(v);

            block = (ImageView) v.findViewById(R.id.block);
        }
    }

    @Override
    public BlockAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(context);

        View view = inflater.inflate(R.layout.block_layout, parent, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        Block block = blocks.get(position);

        // How to use block.getNumBlocks() to show the correct number of blocks?
    }

    @Override
    public int getItemCount() {
        return blocks.size();
    }

}

以下是block_layout.xml(它只是一个空的LinearLayout,应该在此LinearLayout中添加块):

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/card_bg"
    android:padding="16dp">


</LinearLayout>

这是block.xml布局:

<ImageView
    android:id="@+id/block"
    android:layout_width="18dp"
    android:layout_height="18dp"
    android:layout_marginEnd="8dp"
    android:layout_marginRight="8dp" />

所以我的问题是,如何实现这一点,以便它显示每个RecyclerView项目的正确数量的块?

表现明智的最佳方式是什么?

2 个答案:

答案 0 :(得分:2)

你关心表现很好。每次要显示一行时创建新的ImageViews都违背了回收视图的想法。基本上在滚动时,您只会重复使用顶级视图,但每次在屏幕上显示任何项目时仍会创建新的ImageViews

为了解决这个问题,您可以创建自己的视图池:

public class BlockAdapter extends RecyclerView.Adapter<BlockAdapter.ViewHolder> {

    private final List<Block> blocks;
    private final List<ImageView> imageViewPool = new LinkedList<>();

    public BlockAdapter(List<Block> blocks) {
        this.blocks = blocks;
    }

    @Override
    public int getItemCount() {
        return blocks.size();
    }

    @Override
    public BlockAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.block_layout, parent, false));
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        holder.bind(blocks.get(position));
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        private final List<ImageView> imageViews = new ArrayList<>();
        private final ViewGroup container;

        public ViewHolder(View v) {
            super(v);
            container = (ViewGroup) itemView;
        }

        public void bind(Block block) {
            recycleImageViews();
            for (int i = 0; i < block.getNumBlocks(); ++i) {
                final ImageView imageView = getRecycledImageViewOrCreate();
                imageViews.add(imageView);
                container.addView(imageView);
            }
        }

        private ImageView getRecycledImageViewOrCreate() {
            if (imageViewPool.isEmpty()) {
                return (ImageView)LayoutInflater.from(container.getContext()).inflate(R.layout.block, container, false);
            }
            return imageViewPool.remove(0);
        }

        public void recycleImageViews() {
            imageViewPool.addAll(imageViews);
            imageViews.clear();
            container.removeAllViews();
        }
    }

    @Override
    public void onViewRecycled(ViewHolder holder) {
        super.onViewRecycled(holder);
        holder.recycleImageViews();
    }
}

这个解决方案背后的想法与RecyclerView非常相似。

每次ViewHolder想要展示子项时,它都会:

  • imageViewPool获取ImageView。如果池中没有备用的,则新的将膨胀。
  • 将此ImageView附加到自身。

稍后,当重新使用或回收特定ViewHolder时,它将:

  • 从自身分离所有ImageViews
  • 将这些ImageViews返回到可重复使用的池中,以便屏幕上显示的下一个项目可以使用这些项目。

答案 1 :(得分:0)

首先更改viewholader并获取根布局的参考 -

 public class ViewHolder extends RecyclerView.ViewHolder {
    LinearLayout root;

    public ViewHolder(View v) {
        super(v);
        root = (LinearLayout) v.findViewById(R.id.root);
    }
}

之后,内部bindview持有者遍历一个块大小的循环

for(int i=0;i<block.size;i++) {
        ImageView blockImg = new ImageView(context);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
        lp.setMargins(left, top, right, bottom);
        blockImg.setLayoutParams(lp);
        holder.root.addView(blockImg);
    }

使用LayoutParams,您也可以提供所需的边距并将其应用于imageview