问题
I am trying to create a layout with a list of items, where the last item is a button to add a new item of the "standard" type. It should be something like Google Keep lists, with a permanent "add" item at the end of the list. Google Keep list example
I have tried two ways to achieve it. The first one is very simple, but I find a problem. The second one is not that simple, and the performance is worse. In addition, I think with the second way I am using RecyclerView
in a way that is not intended, and I think I could find performance issues due to that.
How would you do it?
First way
The first one should be the easiest, that is adding in the same layout a RecyclerView
followed by a ViewGroup
containing the "add" item. As parent I use a LinearLayout
with the RecyclerView
and an Include
tag referenced to the "add" item layout. This is actually inside a CoordinatorLayout
because I use a BottomSheet
to pick the new "standard" item to be added.
<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>
The problem is that the "add" item is positioned below the RecyclerView
, and both disappear when the RecyclerView
is empty.
Second way
Then I tried the second way, that is creating the "add" item from the RecyclerView.Adapter
. Doing it this way is working so far, although I am sure that this cannot be the best way to do it. I will paste the code and below it I explain the reasoning behind.
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;
}
}
To do so I have created a private variable mCount that I use to count the amount of ViewHolder
created. Then I start my onCreateViewHolder
method with an if statment, where I check if I have already created the ViewHolder
for the last "standard" item of my mDataset. Depending on it I inflate the "standard" view or the "add" view. Then I would have to be updating mCount values each time the user adds or deletes an item (not implemented yet). I also add a tag to the view to get which View
I am using at the ViewHolder
without big troubles.
I have to change the onBindViewHolder
because in case I am inflating the "add" view, I don't want to bind anything as the view is already defined.
I also have to modify the getItemCount
method to return the size of my mDataset plus 1 for the "add" view.
Finally I have to be sending the BottomSheetBehaviour
instance all the way to the ViewHolder
through the Adapter
to be able to open the BottomSheet
with the onClick
defined in the ViewHolder
, which I don't think is very efficient.
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
}
Here I get the tag from the View
, and depending on it I set a different listener.
来源:https://stackoverflow.com/questions/35927007/recyclerview-with-a-different-last-item-as-add-item