简体   繁体   中英

Recyclerview unexpectedly onclick items

I am programming a simple game in android and I encountered a problem with recyclerview . I need help please , tnx :)

I have an activity that create an arrayList and add my data to it then pass it to my recyclerview 's adapter . In the adapter I write code that user can't select more than an image. Now the problem is there when I select first item and then scroll recyclerview I see that one of the last three items is selected. And this case happen for only fist line items and last three items too.

What can I do for that ?

My activity :

public class page_register extends AppCompatActivity {

    Activity _A;
    Context _C;

    private RecyclerView recyclerView1, recyclerView2;
    private AdsAdapter adapter1;
    private Avatar2Adapter adapter2;

    private ArrayList<Ads> adsArrayList;

    TextView Tv1, Tv2;
    EditText ET1, ET2;
    Button BT_First, BT_Second;
    ImageButton BT_Back;
    ImageView img_first, img_second;
    CardView cardView1, cardView2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.page_register);
        M_UI.SetOffKeyboard(this);
        M_Font.Initial(this);

        _A = this;
        _C = this;

        Initial();


        adsArrayList = new ArrayList<>();
        adsArrayList.add(new Ads(R.drawable.a1));
        adsArrayList.add(new Ads(R.drawable.a2));
        adsArrayList.add(new Ads(R.drawable.a3));
        adsArrayList.add(new Ads(R.drawable.a4));
        adsArrayList.add(new Ads(R.drawable.a5));
        adsArrayList.add(new Ads(R.drawable.a6));
        adsArrayList.add(new Ads(R.drawable.a7));
        adsArrayList.add(new Ads(R.drawable.a8));
        adsArrayList.add(new Ads(R.drawable.a9));
        adsArrayList.add(new Ads(R.drawable.a10));
        adsArrayList.add(new Ads(R.drawable.a11));
        adsArrayList.add(new Ads(R.drawable.a12));
        adsArrayList.add(new Ads(R.drawable.a13));
        adsArrayList.add(new Ads(R.drawable.a14));
        adsArrayList.add(new Ads(R.drawable.a15));
        adsArrayList.add(new Ads(R.drawable.a16));             
        adsArrayList.add(new Ads(R.drawable.a17));
        adsArrayList.add(new Ads(R.drawable.a18));
        adsArrayList.add(new Ads(R.drawable.a19));
        adsArrayList.add(new Ads(R.drawable.a20));
        adsArrayList.add(new Ads(R.drawable.a21));
        //--------------------------------------------

        adapter1 = new AdsAdapter(adsArrayList, this, _C, _A, recyclerView1, 0);
        adapter2 = new Avatar2Adapter(adsArrayList, this, _C, _A, recyclerView2, 0);

        RecyclerView.LayoutManager layoutManager1 = new GridLayoutManager(_C, 3);
        RecyclerView.LayoutManager layoutManager2 = new GridLayoutManager(_C, 3);
        recyclerView1.setLayoutManager(layoutManager1);
        recyclerView2.setLayoutManager(layoutManager2);

        recyclerView1.setAdapter(adapter1);
        recyclerView2.setAdapter(adapter2);
    }     

    public void Initial() {
        recyclerView1 = (RecyclerView) findViewById(R.id.recycler_view1);
        recyclerView2 = (RecyclerView) findViewById(R.id.recycler_view2);    

    }
}

and my adapter :

public class AdsAdapter extends RecyclerView.Adapter<AdsAdapter.AdsViewHolder> {

    private ArrayList<Ads> dataList;

    Context _C1;
    Activity _A1;

    RecyclerView r;

    int SelectedPos = 0;

    int id_prev;
    CardView CV_Prev = null;

    public AdsAdapter(ArrayList<Ads> dataList, FragmentActivity activity, Context _C, Activity _A, RecyclerView recyclerView, int i) {
        this.dataList = dataList;

        _A1 = _A;
        _C1 = _C;
        r = recyclerView;

    }


    @Override
    public AdsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        final View view = layoutInflater.inflate(R.layout.avatars, parent, false);


        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View SelectCardView) {

                try {

                    if (CV_Prev != null) {
                        CV_Prev.findViewById(R.id.img_select).setVisibility(View.INVISIBLE);
                    }
                    SelectCardView.findViewById(R.id.img_select).setVisibility(View.VISIBLE);



                    CV_Prev = (CardView) SelectCardView;

                } catch (Exception e) {
                    Toast.makeText(_C1, e.getMessage(), Toast.LENGTH_SHORT).show();
                }
            }
        });

        return new AdsViewHolder(view);
    }

    @Override
    public void onBindViewHolder(AdsViewHolder holder, int position) {

         holder.CV_item.setTag(position);
        //------------------------------------------------------------------
        holder.img_avatar.setImageResource(dataList.get(position).getImage());


    }


    @Override
    public int getItemCount() {
        return dataList.size();
    }


    class AdsViewHolder extends RecyclerView.ViewHolder {

        ImageView img_avatar;
        CardView CV_item;

        AdsViewHolder(View itemView) {
            super(itemView);
            //-----------------------------------------------------------
            img_avatar = (ImageView) itemView.findViewById(R.id.img_avatar);
            CV_item = (CardView) itemView.findViewById(R.id.cardView);

        }

    }
}

my view :

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/cardView"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="#00ffffff"
    android:layoutDirection="ltr"
    android:paddingLeft="5dp"
    android:paddingRight="5dp"
    card_view:cardBackgroundColor="#B2EBF2"
    card_view:cardCornerRadius="5dp"
    card_view:cardElevation="5dp"
    card_view:cardUseCompatPadding="true">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">


        <ImageView
            android:id="@+id/img_avatar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#00ffffff"
            card_view:srcCompat="@drawable/a1" />

        <ImageView
            android:id="@+id/img_select"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:visibility="invisible"
            card_view:srcCompat="@mipmap/ic_check_circle_black_48dp" />


    </RelativeLayout>


</android.support.v7.widget.CardView>

my model :

public class Ads {

    private int image;



    public Ads(int image) 

      {
        this.image = image;
      }



    public void setImage(int image) {this.image = image;}

    public int getImage() {return image;}

  }

below image shows my mean :

在此处输入图片说明

*** I tried to set id for each card and image and selecting them by their id but that didn't help too.

This happens because recycler view recycles the view in OnBindViewHolder.To solve this.

create a global variable to store the clicked position.

private mItemSelected=-1;

Then inside viewholder add the clickListener and onClick store the position of the clicked item.

class AdsViewHolder extends RecyclerView.ViewHolder {

    ImageView img_avatar;
    CardView CV_item;
    AdsViewHolder(View itemView) {
        super(itemView);
        //-----------------------------------------------------------
        img_avatar = (ImageView) itemView.findViewById(R.id.img_avatar);
        CV_item = (CardView) itemView.findViewById(R.id.cardView);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mItemSelected=getAdapterPosition();
                notifyDataSetChanged();
            }
        });

    }

}

And in inside OnBindViewHolder,

if(mItemSelected==position){

//code for image selected.
  holder.CV_item.setVisibility(View.VISIBLE);

}else{

//code for image unselected.
  holder.CV_item.setVisibility(View.INVISIBLE);

}   

Also remove the click listener that has been added in the createViewholder instead add it inside the constructor of AdsViewHolder as added above.

EDIT :Check this updated code.Hope it helps you.

public class AdsAdapter extends RecyclerView.Adapter<AdsAdapter.AdsViewHolder> {

private ArrayList<Ads> dataList;
Context _C1;
Activity _A1;
RecyclerView r;
int SelectedPos = 0;
int id_prev;
CardView CV_Prev = null;
private int mItemSelected=-1;

public AdsAdapter(ArrayList<Ads> dataList, FragmentActivity activity, Context _C, Activity _A, RecyclerView recyclerView, int i) {
    this.dataList = dataList;
    _A1 = _A;
    _C1 = _C;
    r = recyclerView;

}


@Override
public AdsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
    final View view = layoutInflater.inflate(R.layout.avatars, parent, false);
    return new AdsViewHolder(view);
}

@Override
public void onBindViewHolder(AdsViewHolder holder, int position) {

 holder.CV_item.setTag(position);
holder.img_avatar.setImageResource(dataList.get(position).getImage());
    if(mItemSelected==position){

     //code for image selected. 
        holder.CV_item.setVisibility(View.VISIBLE);

    }else{

    //code for image unselected. 
        holder.CV_item.setVisibility(View.INVISIBLE);

    }

}

@Override
public int getItemCount() {
    return dataList.size();
}


class AdsViewHolder extends RecyclerView.ViewHolder {

    ImageView img_avatar;
    CardView CV_item;
    AdsViewHolder(View itemView) {
        super(itemView);
        //-----------------------------------------------------------
        img_avatar = (ImageView) itemView.findViewById(R.id.img_avatar);
        CV_item = (CardView) itemView.findViewById(R.id.cardView);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mItemSelected=getAdapterPosition();
                notifyDataSetChanged();
            }
        });

    }

  }
}

Replace this code

 if (CV_Prev != null && CV_Prev.findViewById(R.id.img_select).getVisibility() == View.VISIBLE) { CV_Prev.findViewById(R.id.img_select).setVisibility(View.INVISIBLE); } if(SelectCardView.findViewById(R.id.img_select).getVisibility() == View.INVISIBLE) SelectCardView.findViewById(R.id.img_select).setVisibility(View.VISIBLE); 

or you can create a global variable to store the clicked position and change its Visibility after second click

See if this helps: https://stackoverflow.com/a/46641850/4469112 I just explained how to properly set the on click listeners to recycler view's adapter and view holders. The important part is to set the listener to the view holder (and no directly to the view), and then to let the view holder to set itself as listener to the passed view. Remember the view is recycled and the content is binded to it at runtime (when you scroll in your case), that's why you're seeing the selection 'transferred' to the other items.

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