问题
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 ViewHolderfor 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