android - 在 RecyclerView 项目中显示动态数量的 View ?

标签 android android-layout android-recyclerview

我正在尝试重新创建这个:

enter image description here

我有一个数据列表:

List<Block> blocks;

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

我创建了一个普通的 RecyclerView 适配器,以及该 block 的 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, block 应该添加到这个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 项目的正确 block 数?

实现性能明智的最佳方法是什么?

最佳答案

您关心性能是件好事。每次想要显示一行时创建新的 ImageViews 违背了回收 View 的想法。基本上,当滚动时,您只会重复使用顶层 View ,但每次出现在屏幕上时仍会为任何项目创建新的 ImageViews

为了解决这个问题,您可以创建自己的 View 池,如下所示:

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 返回到可重用池,以便屏幕上出现的下一个项目可以使用它们。

关于android - 在 RecyclerView 项目中显示动态数量的 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43101231/

相关文章:

android - 如何更改 ExpandableListView 组指示器位置?

Android - 滚动后无法点击 RecyclerView 内的项目

android - 如何从其子 recyclerview View 中获取父 recyclerview 的引用?

java - 覆盖库对 "R.style.someTheme"的引用

android - Android中的gravity和layout_gravity有什么区别?

android - 发生布局更改时设置动画

android - 如何删除我授予自己的 Android OAuth2 权限

android - 如何从eclipse检测android物理设备?

Android:MediaPlayer 启动新 Activity 后未发布而已完成

java - Android Studio,如何从Sqlite 数据库中检索数据并将其显示到textview 中?