-1

I have followed a tutorial here and it works up until a point when I press an individual ImageButton when the user pressed the button and should change the background of that image button here is my XML code for the View that is being sent from the adapter to the recycler

    <?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card"
    android:layout_marginBottom="8dp"
    android:padding="16dp"
    app:cardElevation="1dp"
    app:cardCornerRadius="0dp"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginTop="50dp"
        android:weightSum="1">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/mainPost"
            android:textSize="16sp"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="6dp"
            android:text="skjhdjksdfbjkdsbfjksdbjkbjsdkbjfhbsjfbjhdsbfhjsdbfb"/>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="10dp"
            android:orientation="horizontal"
            android:layout_weight="0.87"
            android:weightSum="2"
            android:id="@+id/relativeCardItem">
<TextView
                android:layout_width="wrap_content"
                android:layout_height="24dp"
                android:textAppearance="?android:attr/textAppearanceListItemSmall"
                android:text="Large Text"
                android:id="@+id/likes"
                android:gravity="left|center_vertical"
                android:layout_centerVertical="true"
                android:layout_marginRight="38dp"
                android:layout_marginEnd="38dp"
                android:layout_alignParentRight="true"/>

            <ImageButton
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:text="New Button"
                android:id="@+id/heart"
                android:layout_alignParentTop="false"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="false"
                android:background="@drawable/ic_favorite_outline_24dp"/>

        </RelativeLayout>
    </LinearLayout>


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

And this is my code for the adapter.

public class IndividualItemsAdapter extends RecyclerView.Adapter<IndividualItemsAdapter.ViewHolder> {
    ArrayList<JSONObject> posts;
    static AppCompatActivity activity;
    static RecyclerView recyclerView;
    private static int current;

    public IndividualItemsAdapter(ArrayList<JSONObject> strings, AppCompatActivity activity, RecyclerView recyclerView) {
        this.posts=strings;
        this.activity=activity;
        this.recyclerView=recyclerView;
    }

    @Override
    public IndividualItemsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_element,parent,false);
        Log.e("Recycler", "We are here");
        ViewHolder holder=new ViewHolder(view, new ViewHolder.MyViewclickHolder() {
            @Override
            public void onCardPress(CardView cardView, int pos) {
                FragmentTransaction ft=activity.getSupportFragmentManager().beginTransaction();
                ft.replace(R.id.main,IndividualPosts.newInstance(pos));
                ft.addToBackStack(null);
                ft.commit();

            }

            @Override
            public void onHeartPress(ImageButton imgB, int pos) {
                ImageButton h= (ImageButton) recyclerView.getChildAt(pos);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    h.setBackground(activity.getDrawable(R.drawable.ic_favorite_24dp));
                }
            }
        });

        return holder;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        try {
            holder.textView.setText(posts.get(position).getString("text"));
            holder.likes.setText(posts.get(position).getString("likes"));


        } catch (JSONException e) {
            e.printStackTrace();
        }


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

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }



    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        CardView cardView;
        TextView textView;
        TextView likes;
        ImageButton heart;
        Yammers yammers;
        MyViewclickHolder myViewclickHolder;
        public ViewHolder(View itemView, MyViewclickHolder myViewclickHolder) {
            super(itemView);
            yammers=Yammers.newInstance();
            cardView= (CardView) itemView.findViewById(R.id.card);
            textView= (TextView) itemView.findViewById(R.id.mainPost);
            likes=(TextView) itemView.findViewById(R.id.likes);
            heart= (ImageButton) itemView.findViewById(R.id.heart);
            this.myViewclickHolder=myViewclickHolder;
            heart.setOnClickListener(this);
            cardView.setOnClickListener(this);



        }
        public interface MyViewclickHolder{
            public void onCardPress(CardView cardView, int pos);
            public void onHeartPress(ImageButton imgB, int pos);
        }

        @Override
        public void onClick(View v) {
            if (v instanceof CardView)
            {
                Log.e("View Holder CardView","is pressed at position"+recyclerView.getChildAdapterPosition(v));

                myViewclickHolder.onCardPress((CardView) v, getLayoutPosition());
            }
            else if (v instanceof ImageButton)
            {
                Log.e("View Holder imageButton","is pressed at position"+getLayoutPosition());

                myViewclickHolder.onHeartPress((ImageButton) v,getLayoutPosition());
            }

        }
    }

}

I have tried this but I get class cast exception and does not work.

ViewHolder holder=new ViewHolder(view, new ViewHolder.MyViewclickHolder() {
            @Override
            public void onCardPress(CardView cardView, int pos) {
                FragmentTransaction ft=activity.getSupportFragmentManager().beginTransaction();
                ft.replace(R.id.main,IndividualPosts.newInstance(pos));
                ft.addToBackStack(null);
                ft.commit();

            }

            @Override
            public void onHeartPress(ImageButton imgB, int pos) {
            current=recyclerView.getChildAdapterPosition(imgB);
            ImageButton h= (ImageButton) recyclerView.getChildAt(current);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                h.setBackground(activity.getDrawable(R.drawable.ic_favorite_24dp));
            }
        });

I tried this one as well but whn I click the favorite button of the list items it changes the background for the individual list item, but also changes the background image for the other list items which I did not press

@Override
        public void onHeartPress(ImageButton imgB, int pos) {

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                imgB.setBackground(activity.getDrawable(R.drawable.ic_favorite_24dp));
            }
        }

This is my ViewHolderClass

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    CardView cardView;
    TextView textView;
    TextView likes;
    ImageButton heart;
    Yammers yammers;
    MyViewclickHolder myViewclickHolder;
    public ViewHolder(View itemView, MyViewclickHolder myViewclickHolder) {
        super(itemView);
        yammers=Yammers.newInstance();
        cardView= (CardView) itemView.findViewById(R.id.card);
        textView= (TextView) itemView.findViewById(R.id.mainPost);
        likes=(TextView) itemView.findViewById(R.id.likes);
        heart= (ImageButton) itemView.findViewById(R.id.heart);
        this.myViewclickHolder=myViewclickHolder;
        heart.setOnClickListener(this);
        cardView.setOnClickListener(this);



    }
    public interface MyViewclickHolder{
        public void onCardPress(CardView cardView, int pos);
        public void onHeartPress(ImageButton imgB, int pos);
    }

    @Override
    public void onClick(View v) {
        if (v instanceof CardView)
        {
            Log.e("View Holder CardView","is pressed at position"+recyclerView.getChildAdapterPosition(v));

            myViewclickHolder.onCardPress((CardView) v, getLayoutPosition());
        }
        else if (v instanceof ImageButton)
        {
            Log.e("View Holder imageButton","is pressed at position"+getLayoutPosition());

            myViewclickHolder.onHeartPress((ImageButton) v,getLayoutPosition());
        }

    }
}
Community
  • 1
  • 1
john doe
  • 157
  • 1
  • 10

3 Answers3

0
  ImageButton h= (ImageButton) recyclerView.getChildAt(pos);

Will get the whole view and not only the image button. Since the enclosing layout is a CardView you will get only cardview object her.

Create an interface to capture the click of image button and then change its background.

Ragesh Ramesh
  • 3,470
  • 2
  • 14
  • 20
  • If your aim is to just change the background of the imageButton then you can do it inside the adapter itself(though this is not the proper standard) and call notify item changed. – Ragesh Ramesh Feb 16 '16 at 05:26
0

There are several things at play here. When you do this

ImageButton h= (ImageButton) recyclerView.getChildAt(pos);

It will return the root layout of the list item. In this case it is a CardView!

This should be the correct way to go about what you are doing

@Override
public void onHeartPress(ImageButton imgB, int pos) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
       imgB.setBackground(activity.getDrawable(R.drawable.ic_favorite_24dp));
    }
}

I click the favorite button of the list items it changes the background for the individual list item, but also changes the background image for the other list items which I did not press

The reason for this is View Recycling. That's what RecyclerView does. It does not create views for every item in your ArrayList. Rather it re-uses views created earlier. That's why you always need to update the state of the item in onBindViewHolder method.

So you would do the following

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    try {
          holder.textView.setText(posts.get(position).getString("text"));
          holder.likes.setText(posts.get(position).getString("likes"));
          //update the background of the heart image here based on whether or not 
          //it was ticked

      } catch (JSONException e) {
          e.printStackTrace();
      }
}

You have to maintain which items have been hearted in your adapter. For this you could use a SparseBooleanArray

Much Overflow
  • 3,142
  • 1
  • 23
  • 40
0

Find your ImagButton from fetched view.

final View rootView = recyclerView.getChildAt(pos);
final ImageButton ibHeart = (ImageButton)   
 rootView.findviewById (R.id.heart);

If still it doesn't work for you. Please add logs in your question.

Rahul
  • 10,457
  • 4
  • 35
  • 55
  • It still does not work When I pressed it changes the background of the imagebutton but only for that list item other items that I have not pressed as well – john doe Feb 16 '16 at 05:31
  • Yes because its a recyclerview. Same view can be reused by other items. Its good to maintain extra parameter in your model class which will define which item is selected or which not and then you can use notify on your adapter. – Rahul Feb 16 '16 at 05:35
  • I tried to add the using this array.append(recyclerView.getChildAdapterPosition(v),true); and then checked on onCreateViewHolder but now I am getting RelativeLayout$LayoutParams cannot be cast to android.support.v7.widget.RecyclerView$LayoutParams – john doe Feb 16 '16 at 06:33