-4

Hi I am have a question regarding CardViews in a RecyclerView.My CardViews basically has 2 segments i.e. the base card and the expanded card. My OnClick just sets the setVisibility property of each segment to either GONE or VISIBLE. Right now my OnClickListener is in the OnBindViewHolder method. I have read that it is better to put it in the ViewHolder class, however, I am not sure how to achieve the same result at this moment. My main problem is best represented by the images below:

This is the default way the images should be displayed or "base_view"

Base CardView

When you click on the image, the card will show information related to that card, aka the "expanded_view".

Expanded CardView on Click

How can I prevent the other CardViews(the middle and right card) from changing (from a square to the long rectangle) when I change the layout of one card? Example as follows:

enter image description here

This is my CardView XML:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/tools"
android:layout_gravity="center"
app:cardCornerRadius="8dp"
android:layout_margin="1dp"
android:id="@+id/cv_army">


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

<RelativeLayout
    android:layout_width="90dp"
    android:layout_height="90dp"
    android:orientation="vertical"
    android:id="@+id/base_card">

    <ImageView
        android:layout_width="90dp"
        android:layout_height="120dp"
        android:layout_margin="2dp"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:src="@drawable/summon_cm"
        android:scaleType="fitCenter"
        android:id="@+id/iv_card"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/iv_card"
        android:layout_marginBottom="10dp"
        android:layout_centerHorizontal="true"
        android:textColor="#000"
        android:text="Test"
        android:textAllCaps="false"
        android:textSize="10dp"
        android:textAlignment="center"
        android:background="#ffffff"
        android:backgroundTint="@color/trans_success_stroke_color"
        android:id="@+id/tv_card"/>

</RelativeLayout>

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="150dp"
    android:layout_gravity="center"
    android:background="@color/colorPrimaryDark"
    android:id="@+id/expanded_card">

    <TextView
        android:layout_width="90dp"
        android:layout_height="wrap_content"
        android:id="@+id/card_popup_name"
        android:layout_alignParentTop="true"
        android:layout_marginTop="5dp"
        android:layout_centerHorizontal="true"
        android:text="Card Name"/>


    <ImageView
        android:layout_width="90dp"
        android:layout_height="80dp"
        android:src="@drawable/bg_summon"
        android:scaleType="fitCenter"
        android:id="@+id/card_popup_img"
        android:layout_below="@id/card_popup_name"
        android:layout_marginTop="5dp"
        android:layout_centerHorizontal="true"/>

    <TextView
        android:layout_width="35dp"
        android:layout_height="wrap_content"
        android:layout_below="@id/card_popup_img"
        android:layout_marginTop="10dp"
        android:layout_alignStart="@id/card_popup_img"
        android:id="@+id/card_popup_hp"
        android:text="HP"
        android:textAlignment="viewEnd"
        android:layout_gravity="end"/>

    <TextView
        android:text="123"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/card_popup_hp"
        android:layout_alignStart="@id/card_popup_img"
        android:layout_marginStart="45dp"
        android:id="@+id/tv_hp" />

    <Button
        android:text="Use"
        android:textSize="10dp"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="5dp"
        android:layout_centerHorizontal="true"
        android:id="@+id/btn_use" />
</RelativeLayout>

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

I put my onBindView here as well just in case it is necessary:

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

    holder.base_card.setVisibility(View.VISIBLE);
    holder.expanded_card.setVisibility(View.GONE);
    final int p = position;
    String s = card_list.get(p).card_name;
    final String sx = s.substring(1); //The 1st position [index 0] stores the rarity of the card, so remove that from the string to get the name
    holder.tv_card.setText(sx);
    holder.iv_card.setImageResource(card_list.get(p).card_img);

    //RV_Animator.animate(holder);

    holder.iv_card.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

        holder.expanded_card.setVisibility(View.VISIBLE);
        holder.base_card.setVisibility(View.GONE);

            for (int ix =0; ix<getItemCount();ix++){
                if (ix!=p){
                    notifyItemChanged(ix);
                }
            }

        }
    });

    holder.expanded_card.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View vy) {
            holder.expanded_card.setVisibility(View.GONE);
            holder.base_card.setVisibility(View.VISIBLE);
        }
    });

    holder.btn_use.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View vx) {
            new SweetAlertDialog(context, SweetAlertDialog.SUCCESS_TYPE)
                    .setTitleText("Success!")
                    .setContentText("asd")
                    .show();
        }
    });
}

2 Answers2

1

For this you have to store the position of item which you have clicked, say int mClickedPosition

then in onBindViewHolder() method , you have to check if the current position is same as mClickedPosition, just make the expandedview to VISIBLE, else for other position, make it GONE.

inside your onBindViewHolder, you have to check something like this

if (mClickedPosition == position) {
        holder.base_card.setVisibility(View.GONE);
        holder.expanded_card.setVisibility(View.VISIBLE);
    } else {
        holder.base_card.setVisibility(View.VISIBLE);
        holder.expanded_card.setVisibility(View.GONE);
    }

updated the whole sample adapter code as requested :

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {


    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View content_view = inflater.inflate(R.layout.list_item,parent,false);
        MyViewHolder holder = new MyViewHolder(content_view);
        return holder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, int position) {
        holder.base_card.setVisibility(View.VISIBLE);
        holder.expanded_card.setVisibility(View.GONE);
        final int p = position;
        String s = "hasif";//card_list.get(p).card_name;
       // final String sx = s.substring(1); //The 1st position [index 0] stores the rarity of the card, so remove that from the string to get the name
        holder.tv_card.setText(s);
        //holder.iv_card.setImageResource(card_list.get(p).card_img);

        //RV_Animator.animate(holder);

        holder.iv_card.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                holder.expanded_card.setVisibility(View.VISIBLE);
                holder.base_card.setVisibility(View.GONE);

                for (int ix =0; ix<getItemCount();ix++){
                    if (ix!=p){
                        notifyItemChanged(ix);
                    }
                }

            }
        });

        holder.expanded_card.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View vy) {
                holder.expanded_card.setVisibility(View.GONE);
                holder.base_card.setVisibility(View.VISIBLE);
            }
        });

        holder.btn_use.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View vx) {
                //Toast.makeText()
            }
        });
    }

    @Override
    public int getItemCount() {
        return 3;
    }

    public static class MyViewHolder extends RecyclerView.ViewHolder {

        private ImageView iv_card;
        private TextView tv_card;
        private RelativeLayout expanded_card;
        private RelativeLayout base_card;
        private Button btn_use;
        public MyViewHolder(View itemView) {
            super(itemView);
            iv_card = (ImageView) itemView.findViewById(R.id.iv_card);
            tv_card = (TextView) itemView.findViewById(R.id.tv_card);
            expanded_card = (RelativeLayout) itemView.findViewById(R.id.expanded_card);
            base_card = (RelativeLayout) itemView.findViewById(R.id.base_card);
            btn_use = (Button) itemView.findViewById(R.id.btn_use);

        }
    }
}
Hasif Seyd
  • 1,686
  • 12
  • 19
  • Hi Hasif, thanks for the reply. I don't follow your answer, isnt `onBindViewHolder()` called for each card position? Then, position would be a given. If not all cards, based on my code, would change to the expanded view. Appreciate if you elaborate if I am misunderstanding. – Imran Hamid Jan 13 '17 at 03:16
  • @ImranHamid yes onBindViewHolder() method will be called for each item, but you have to show the expandedView for only that item which is been selected by the user, so you have to check for that position item when onBindViewHolder is getting called, check my edited answer above – Hasif Seyd Jan 13 '17 at 03:37
  • my main issue actually is the center and right cards becoming "longer". The base layout is `wrap_content` around the `ImageView`. When my 1st card gets set to the expanded layout, you can see the other 2 card no longer have a `wrap_content` style – Imran Hamid Jan 13 '17 at 03:52
  • @ImranHamid that is what i am trying to say, for example, if you have selected the first card, then mSelectedPosition=0, so only for 1st card-item, it will show the expanded View and for 2nd and 3rd card, it will show square, did you see the code Snippet which i have posted in my answer . you have to do like that. – Hasif Seyd Jan 13 '17 at 03:59
  • @ImranHamid at what condition you change the layout of first card ? you must be clicking on that layout right ? at that time, you have to see the expanded view ? this is what i understood. is it correct? – Hasif Seyd Jan 13 '17 at 04:04
  • that is correct, the layout only changes when the `ImageView` on the Card is clicked. I have put an `onclicklistener` in my `onBindViewHolder`. Thus, my understanding is each card's `ImageView` has a Listener. The `VISIBLE` and `GONE` properties are being set correctly for the ImageView i click, but it happens to change the dimensions of the other Card's layout. Since I already have an `onClickListener` per card, it confused me when you ask me check the position of the card. Am i putting my `onClickListener` in the wrong place? – Imran Hamid Jan 13 '17 at 06:16
  • I have put in a picture of the result i want above. The 2nd image is what my app currently gives. – Imran Hamid Jan 13 '17 at 06:29
  • @ImranHamid i have tried your xml and code whatever you have written in onBindview, and its working perfectly for me , – Hasif Seyd Jan 13 '17 at 07:07
  • the cards other than the ones you click remain as proper squares? – Imran Hamid Jan 13 '17 at 09:45
  • @ImranHamid yes exactly – Hasif Seyd Jan 13 '17 at 10:55
  • do you mind sharing with me the other parts of your code for the Adapter? e,g, the ViewHolder class? Maybe I am doing something wrong there. – Imran Hamid Jan 13 '17 at 11:08
  • @ImranHamid check my updated answer, i have did nothing much change, just posted your logic in onBindViewHolder, and it works for me , i can post screenshot if you want. – Hasif Seyd Jan 13 '17 at 11:18
0
@Override
public int getItemViewType(int position) {
     //More to come
}

Override this method in your RecyclerAdapter and pass Appropriate int type ViewType

 @Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

  RecyclerView.ViewHolder viewHolder;
  LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());

  switch (viewType) {
      case USER:
          View v1 = inflater.inflate(R.layout.layout_viewholder1, viewGroup, false);
          viewHolder = new ViewHolder1(v1);
          break;
      case IMAGE:
          View v2 = inflater.inflate(R.layout.layout_viewholder2, viewGroup, false);
          viewHolder = new ViewHolder2(v2);
          break;
      default:
          View v = inflater.inflate(android.R.layout.simple_list_item_1, viewGroup, false);
          viewHolder = new RecyclerViewSimpleTextViewHolder(v);
          break;
  }
  return viewHolder;

}

Inflate corresponding view based on viewType

refer the link: https://guides.codepath.com/android/Heterogenous-Layouts-inside-RecyclerView

Milind Mevada
  • 3,145
  • 1
  • 14
  • 22
  • Hi Milind, the Card's layout.xml does not change. It just sets certain components of the layout to either VISIBLE or GONE. I believe I do not require 2 viewTypes. – Imran Hamid Jan 13 '17 at 06:25