Recyclerview使用不同的最后一项作为"添加"项目

Dan*_*ina 7 performance android android-layout android-recyclerview

我想用的物品,其中最后一个项目是一个按钮,添加了"标准"类型的新项目列表中创建的布局.它应该像Google Keep列表一样,在列表的末尾有一个永久的"添加"项. Google Keep列表示例

我尝试了两种方法来实现它.第一个很简单,但我发现了一个问题.第二个并不那么简单,性能更差.另外,我认为我使用的第二种方式RecyclerView是非预期的方式,我认为我可以找到性能问题.

你会怎么做?

第一种方式

第一个应该是最简单的,即添加相同的布局a,RecyclerView然后ViewGroup包含"添加"项.作为父级,我使用LinearLayout带有"添加"项布局的RecyclerViewInclude标记.这实际上是在一个CoordinatorLayout因为我使用a BottomSheet来选择要添加的新"标准"项目.

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorBackgroundLight"
    android:orientation="vertical">

    <!-- Other Views -->

    <android.support.v7.widget.RecyclerView
        android:id="@+id/mainRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <include
        layout="@layout/itemAdd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
Run Code Online (Sandbox Code Playgroud)

问题是"添加"项位于下方RecyclerView,并且当它RecyclerView为空时都消失.

第二种方式

然后我尝试了第二种方法,即从中创建"添加"项RecyclerView.Adapter.到目前为止,这样做是有效的,尽管我确信这不是最好的方法.我将粘贴代码,在下面我解释背后的原因.

适配器

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private final LayoutInflater mInflater;
    private BottomSheetBehavior bottomSheetBehavior;
    private int count = 0;
    private final List<Object> mDataset;

    // Standard constructor. I get the mInflater from Context here

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View itemView;
        if (count>=mDataset.size()) {
            itemView = mInflater.inflate(R.layout.item_add, parent, false);
            itemView.setTag("ADD");
        }
        else{
            itemView = mInflater.inflate(R.layout.item_sandard, parent, false);
            itemView.setTag(null);
        }
        count += 1;
        return new MyViewHolder(itemView, bottomSheetBehavior);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        if (position<mDataset.size()) {
            final Object object = mDataset.get(position);
            holder.bind(object); // I bind it on the ViewHolder
        }
    }

    @Override
    public int getItemCount() {
        return mDataset.size()+1;
    }
}
Run Code Online (Sandbox Code Playgroud)

为此,我创建了一个私有变量mCount,用于计算ViewHolder创建的数量.然后我onCreateViewHolderif语句启动我的方法,在那里我检查我是否已经创建了mDatasetViewHolder的最后一个"标准"项.根据它,我膨胀"标准"视图或"添加"视图.然后,每次用户添加或删除项目(尚未实现)时,我都必须更新mCount值.我还在视图中添加了一个标签,以便在没有大麻烦的情况下使用它.ViewViewHolder

我必须更改,onBindViewHolder因为如果我正在膨胀"添加"视图,我不想绑定任何东西,因为视图已经定义.

我还必须修改getItemCount方法以返回mDataset的大小加上"添加"视图的1.

最后,我已经被发送BottomSheetBehaviour一路实例的ViewHolder通过Adapter才能够打开BottomSheetonClick中定义的ViewHolder,我不认为这是非常有效的.

ViewHolder

public class MyViewHolder extends RecyclerView.ViewHolder{
    private final TextView mText;
    private final ImageButton mButton;


    public MyViewHolder(View itemView, final BottomSheetBehavior bottomSheetBehavior) {
        super(itemView);

        if (itemView.getTag() == "ADD"){
            mText = null;
            mButton = null;
            // I also set the OnClickListener to open the BottomSheet
        }
        else{
            // Set mText and an OnClickListener to the button. I use the Adapter here
        }
    }

    // The bind method goes here 
}
Run Code Online (Sandbox Code Playgroud)

在这里我从中获取标签View,并根据它设置不同的监听器.

小智 2

我可能会迟到,但如果您还没有找到任何解决方案,请尝试这种方式..!!


    class AddMorePhotosAdapter(
    val context: Context,
    private val addImageListener: () -> Unit
) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private val imageList = ArrayList<Bitmap>()
    fun addAll(list: ArrayList<Bitmap>) {
        imageList.clear()
        imageList.addAll(list)
        notifyDataSetChanged()
    }

    inner class MyItemHolder(val binding: ItemSelectedPhotoBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(path: Bitmap, position: Int) {
            Glide.with(context)
                .asBitmap()
                .placeholder(R.mipmap.ic_launcher)
                .load(path)
                .into(object : SimpleTarget<Bitmap>() {
                    override fun onResourceReady(
                        resource: Bitmap,
                        transition: Transition<in Bitmap>?
                    ) {
                        binding.tvSelectedImage.apply {
                            setImageBitmap(resource)
                            scaleType = ImageView.ScaleType.FIT_XY
                        }
                    }
                })
        }
    }

    inner class MyFooterHolder(val binding: LayoutMultiplePhotoBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind() {
            binding.tvAddImage.setOnClickListener {
                addImageListener.invoke()
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val binding: ViewBinding
        if (viewType == TYPE_ITEM) {
            binding =
                ItemSelectedPhotoBinding.inflate(LayoutInflater.from(context), parent, false)
            return MyItemHolder(binding)
        } else if (viewType == TYPE_FOOTER) {
            binding =
                LayoutMultiplePhotoBinding.inflate(LayoutInflater.from(context), parent, false)
            return MyFooterHolder(binding)
        }
        throw RuntimeException("There is no type that matches the type $viewType. Make sure you are using view types correctly!")
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (getItemViewType(position)) {
            TYPE_ITEM -> (holder as MyItemHolder).bind(imageList[position], position)
            TYPE_FOOTER -> (holder as MyFooterHolder).bind()
        }
    }

    override fun getItemCount(): Int = imageList.size + 1

    override fun getItemViewType(position: Int): Int {
        return if (position == imageList.size) {
            TYPE_FOOTER
        } else {
            TYPE_ITEM
        }
    }

    companion object {
        private const val TYPE_ITEM = 1
        private const val TYPE_FOOTER = 0
    }
}

Run Code Online (Sandbox Code Playgroud)

-- 我使用 TYPE_TIME 来显示带有 recyclerview 的列表,并使用 TYPE_FOOTER 来显示“添加”图像。两种布局的充气方式都会有所不同。

检查此图像以供参考。最初它只是“添加”图像