I have a Fragment
inside of my MainActivity
that contains a RecyclerView
being populated by a RecyclerView.Adapter
. The RecyclerView
inflates row_layout.xml
file, which has one EditText
and one ImageButton
, like this:
The button is initially loaded with an "add" image. When clicked, my adapter does this:
package com.fragments.homework04;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import java.util.ArrayList;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
public static int positionAdapter;
private ArrayList<ItemData> itemsData;
AdapterButtonInterface mListener;
public MyAdapter(ArrayList<ItemData> itemsData, AdapterButtonInterface adapterButtonInterface) {
this.itemsData = itemsData;
try{
mListener = adapterButtonInterface;
}
catch(ClassCastException e){
throw new ClassCastException("Class does not implement interface!");
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public EditText txtIngredients;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtIngredients = itemLayoutView.findViewById(R.id.etIngredientName);
imgViewIcon = itemLayoutView.findViewById(R.id.btnAddRemoveIngredient);
}
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, null);
Log.d("itemsSizeAdapter", String.valueOf(itemsData.size()));
ViewHolder viewHolder = new ViewHolder(itemLayoutView);
return viewHolder;
}
@Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
viewHolder.imgViewIcon.setTag(itemsData.get(position).getTag());
viewHolder.imgViewIcon.setImageResource(itemsData.get(position).getImageUrl());
viewHolder.imgViewIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
positionAdapter = viewHolder.getAdapterPosition();
if(itemsData.get(position).getTag().contains("Add")){
if(getItemCount() < 5){
itemsData.get(position).setIngredientValue(viewHolder.txtIngredients.getText().toString());
mListener.addBtnClicked(positionAdapter, getItemCount(), itemsData.get(position).getIngredientValue());
}
}
else{
if(getItemCount() > 0){
Log.d("adapterPosition:", String.valueOf(position));
mListener.removeBtnClicked(positionAdapter, getItemCount());
}
}
}
});
}
// Return the size of your itemsData (invoked by the layout manager)
@Override
public int getItemCount() {
return itemsData.size();
}
public interface AdapterButtonInterface{
void addBtnClicked(int position, int itemCount, String ingredientValue);
void removeBtnClicked(int position, int itemCount);
}
}
Basically calls the method in the interface, that is being implemented by my fragment. In my fragment, I am doing this:
ArrayList<ItemData> itemsData;
public void addBtnClicked(int position, int itemCount, String ingredientValue) {
if(itemCount == 4){
//Requirement that there can only be 5 rows at any time.
//Hence when itemCount == 4, we are adding the 5th row and it needs to be a remove instead of add
itemsData.add(position + 1, new ItemData("Remove" + itemCount, R.mipmap.remove_ing, ""));
}
else{
itemsData.add(position + 1, new ItemData("Add" + itemCount, R.mipmap.add_ing, ""));
}
//When the row is added, the EditText's value isn't stored anywhere
//So I am adding it to the arraylist I have
itemsData.get(position).setIngredientValue(ingredientValue);
itemsData.get(position).setImageUrl(R.mipmap.remove_ing);
itemsData.get(position).setTag("Remove");
mAdapter.notifyDataSetChanged();
}
@Override
public void removeBtnClicked(int position, int itemCount) {
Log.d("listenerPosition:", String.valueOf(position));
itemsData.remove(position);
if(itemCount == 5){
itemsData.get(3).setImageUrl(R.mipmap.add_ing);
itemsData.get(3).setTag("Add3");
}
mAdapter.notifyDataSetChanged();
}
A good bit of this works perfectly. When my app loads, I see one EditText and one ImageButton. When I click the ImageButton for the first time, it adds my second EditText and my second ImageButton underneath my first.
BUT, the problem arises when I click my button the second time. The third row gets inserted in the top of the RecyclerView
instead of the bottom. My already existent 1st and 2nd rows get pushed down (along with the contents of the EditText), and my newly added row goes to the top of the recycler.
It gets even weirder, when I click on the "remove" button on my newly inserted top row. It removes one row (as expected) and it clears all my EditTexts (WHY).
If anyone can look at this and tell me where I am making a mistake, I'd appreciate it. I can provide more of my code if needed.
You specify that the position is final
in the ViewHolder
so you can reference it in the onClick()
handler. Since that variable is final
it will not change regardless of any new position that the ViewHolder
may take. Instead of a final
variable, try using getAdapterPosition()
.
getAdapterPosition
int getAdapterPosition ()
Returns the Adapter position of the item represented by this ViewHolder.
This may not be your problem, but give it a try.
Use this two methods in adapter
@Override
public long getItemId(int position) {
return super.getItemId(position);
}
@Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.