简体   繁体   中英

RecyclerView Adapter inserting rows in weird positions

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM