AJW
AJW

Reputation: 1649

RecyclerView: how to add OnClick() and keep onLongClick() working?

I have an onClickListener set on a CheckBox for a RecyclerView that holds a list of CardViews. The listener is set up in my ItemHolder that extends ViewHolder. An initial click on a CardView checks the CheckBox and toggles the CardView's background color from the default white color to red. This is working properly.

I also have an OnClickListener set up on the CardView itself. The OnClickListener is set up in the onCreateViewHolder(). A click on the CardView launches a new Detail Activity for the CardView. This is working properly.

Lastly, I tried to set up an onLongClickListener on the CardView itself. The OnLongClickListener is set up in the onCreateViewHolder(). A longpress on the CardView is meant to toggle the background color to red and launch an AlertDialog so the user can confirm that the CardView will be deleted from the list. This works properly but when this code is added to the Adapter then the OnClickListerner for the CardView's CheckBox no longer works. It is as if the the OnLongClickListner is in conflict with the CheckBox listener. Note I do "return true" in the itemHolder's onLongClick() code. What am I missing here?

Adapter.java

public MyRecylerAdapter(Context context, ArrayList<ListItem> listItems, ArrayList<ListItem> selectedList) {
    this.mContext = context;
    this.mListItems = listItems;
    this.selectedItemsList = selectedList;
}

private int selectedPos = -1;
...

private class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    private CardView cardView;
    private CheckBox chkSelected;

    private ItemHolder(final View itemView) {
        super(itemView);

        cardView = (CardView) itemView.findViewById(R.id.singlecard_view1);
        chkSelected = (CheckBox) itemView.findViewById(R.id.chkSelected);
        chkSelected.setOnClickListener(this);
    }

    public void onClick(View v) {

        int adapterPos = getAdapterPosition();

        if (adapterPos == android.support.v7.widget.RecyclerView.NO_POSITION) return;
        if (recyclerItemClickListener !=null) {
            recyclerItemClickListener.onCheckBoxClick(v, adapterPos);
        }
        Integer iPos = adapterPos;

        if (((CheckBox)v).isChecked()) {
            checkedListItems.add(iPos);
        }
        else {
            checkedListItems.remove(iPos);
        }
    }

    void bind(int position) {

        if (checkedListItems.contains(position)) {
            chkSelected.setChecked(true);
        }
        else {
            chkSelected.setChecked(false);
        }
    }
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false);
    final ItemHolder itemHolder = new ItemHolder(view);

        itemHolder.itemView.setOnClickListener(new View.OnClickListener() {
            // Handles the row being clicked.
            @Override
            public void onClick(View view) {

                ListItem adapterItem = MyRecylerAdapter.this.getItem(itemHolder.getAdapterPosition()); 

                if (recyclerItemClickListener != null) {
                    recyclerItemClickListener.onItemClick(itemHolder.itemView, adapterItem);
                }
            }
        });

        itemHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {

                ListItem adapterItem2 = MyRecylerAdapter.this.getItem(itemHolder.getAdapterPosition()); 

                    if (recyclerItemClickListener != null) {
                        recyclerItemClickListener.onItemLongClick(itemHolder.itemView, adapterItem2);
                    }

                int adapterPos2 = itemHolder.getAdapterPosition(); 
                if (adapterPos2 != android.support.v7.widget.RecyclerView.NO_POSITION) {
                    int lastSelectedPosition = selectedPos;
                    selectedPos = adapterPos2;
                    notifyItemChanged(lastSelectedPosition);
                    notifyItemChanged(selectedPos);
                }                    
                return true;
            }
        });
    return itemHolder;
}

public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {

    final ListItem listItem = mListItems.get(position);
    final ItemHolder itemHolder = (ItemHolder) holder;

    itemHolder.bind(position);

    if (checkedListItems.contains(position)) {
        itemHolder.cardView.setActivated(true);
    }
    else {
        itemHolder.cardView.setActivated(false);
    }        

    // **The addition of the below code causes the "itemHolder.cardView.
    // setActivated(true);" in onBindViewHolder method to no longer fire, as 
    // a click on the CheckBox no longer changes the CardView background 
    // color.**
    if (itemHolder.getAdapterPosition() == selectedPos) {
        itemHolder.cardView.setActivated(true);
    } else {
        itemHolder.cardView.setActivated(false);
    }

list_contact_item.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/singlecard_view1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:foreground="?android:attr/selectableItemBackground"
     >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/statelist_cardview_background"  >

    <CheckBox
        android:id="@+id/chkSelected"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="4dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:gravity="center"  />

    <TextView
        android:id="@+id/cardType1"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_toRightOf="@+id/chkSelected"
        android:layout_toEndOf="@+id/chkSelected"
        android:layout_alignParentTop="true"
        android:paddingStart="3dp"
        android:paddingLeft="3dp"
        android:paddingEnd="6dp"
        android:paddingRight="6dp"
        android:layout_marginTop="4dp"
        android:gravity="center"
        android:textColor="#ffffff"
        android:textStyle="bold|italic"
        style="@style/Base.TextAppearance.AppCompat.Subhead"  />

    <TextView
        android:id="@+id/cardBlankText1"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/cardType1"
        android:layout_toEndOf="@+id/cardType1"
        android:layout_toLeftOf="@+id/cardBlankTextNumstotal"
        android:layout_toStartOf="@+id/cardBlankTextNumstotal"
        android:layout_marginTop="4dp"
        android:gravity="center_vertical|end"
        android:text="#"
        android:textColor="@color/colorFlLabelFinal"
        android:textStyle="bold"
        android:maxLines="1"
        style="@style/Base.TextAppearance.AppCompat.Subhead"  />

    <TextView
        android:id="@+id/cardBlankTextNumstotal"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:gravity="center"
        android:text="actual card #"
        android:layout_marginTop="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginEnd="4dp"
        android:freezesText="true"
        android:textColor="@android:color/black"
        android:maxLines="1"
        style="@style/Base.TextAppearance.AppCompat.Subhead"  />        

    <TextView
        android:id="@+id/cardBlankText2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/chkSelected"
        android:layout_marginTop="4dp"
        android:layout_marginLeft="6dp"
        android:layout_marginStart="6dp"
        android:text="todo"
        android:textColor="@android:color/black"
        android:textStyle="bold"
        android:background="@drawable/todo_underline"
        android:maxLines="1"
        style="@style/Base.TextAppearance.AppCompat.Headline"  />

    ...
    </RelativeLayout>

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

statelist_cardview_background.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_activated="true"

        android:drawable="@color/item_selected" />

    <item android:state_activated="false"

        android:drawable="@color/list_contact_item_default"  />

</selector>

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="list_contact_item_default">#FFFFFF</color>
    <color name="item_selected">#FF0000</color>

</resources>

Upvotes: 7

Views: 3963

Answers (5)

Akhil
Akhil

Reputation: 6697

It seems you are trying to solve the wrong problem here. You should not set click & long click listeners on card view itself.

  • You can have click listener OR checkedChangeListener on Checkbox
  • click & long click listeners can be on rest of the view_container

Here if you want to check/uncheck the checkbox also on click of view_container, you can easily do it in view_container's onClick listener.

Edit: I have updated your layout file, notice now you have on FrameLayout as parent of RelativeLayout(view_container) & Checkbox.

As Checkbox is added after RelativeLayout it will be visible on top of view_container. Hope it will work for you.

Now you can set click listeners as I explained above.

Updated layout file

<?xml version="1.0" encoding="utf-8"?>

<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/singlecard_view1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:foreground="?android:attr/selectableItemBackground"
    >
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/view_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/statelist_cardview_background"  >


        <TextView
            android:id="@+id/cardType1"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_marginLeft="30dp"
            android:layout_marginStart="30dp"
            android:layout_alignParentTop="true"
            android:paddingStart="3dp"
            android:paddingLeft="3dp"
            android:paddingEnd="6dp"
            android:paddingRight="6dp"
            android:layout_marginTop="4dp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:textStyle="bold|italic"
            style="@style/Base.TextAppearance.AppCompat.Subhead"  />

        <TextView
            android:id="@+id/cardBlankText1"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_alignParentTop="true"
            android:layout_toRightOf="@+id/cardType1"
            android:layout_toEndOf="@+id/cardType1"
            android:layout_toLeftOf="@+id/cardBlankTextNumstotal"
            android:layout_toStartOf="@+id/cardBlankTextNumstotal"
            android:layout_marginTop="4dp"
            android:gravity="center_vertical|end"
            android:text="#"
            android:textColor="@color/colorFlLabelFinal"
            android:textStyle="bold"
            android:maxLines="1"
            style="@style/Base.TextAppearance.AppCompat.Subhead"  />

        <TextView
            android:id="@+id/cardBlankTextNumstotal"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_alignParentTop="true"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:gravity="center"
            android:text="actual card #"
            android:layout_marginTop="4dp"
            android:layout_marginRight="4dp"
            android:layout_marginEnd="4dp"
            android:freezesText="true"
            android:textColor="@android:color/black"
            android:maxLines="1"
            style="@style/Base.TextAppearance.AppCompat.Subhead"  />

        <TextView
            android:id="@+id/cardBlankText2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_marginTop="34dp"
            android:layout_marginLeft="6dp"
            android:layout_marginStart="6dp"
            android:text="todo"
            android:textColor="@android:color/black"
            android:textStyle="bold"
            android:background="@drawable/todo_underline"
            android:maxLines="1"
            style="@style/Base.TextAppearance.AppCompat.Headline"  />

        ...
    </RelativeLayout>
        <CheckBox
            android:id="@+id/chkSelected"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_alignParentTop="true"
            android:layout_alignParentStart="true"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="4dp"
            android:layout_marginStart="4dp"
            android:layout_marginTop="4dp"
            android:gravity="center"  />

    </FrameLayout>


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

Upvotes: 0

Martin Yu
Martin Yu

Reputation: 311

you should give you data(mListItems) add a isChecked Fileds!and you can do this

holder.checkebox.setchecked(false);
if(mListItems.get(position).ischekced){
 holder.checkebox.setchecked(true);
}
holder.checkebox..setOnCheckedChangeListener(new OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
  mListItems.get(position).isChecked=isChecked;

}
});

Upvotes: 0

AppHero2
AppHero2

Reputation: 687

How come you are not using OnCheckedChangeListener for checkbox?

CheckBox chkBox = ( CheckBox ) findViewById( R.id.checkbox );
chkBox.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
    {
        if ( isChecked )
        {
            // perform logic
        }

    }
});

Upvotes: 2

Reyansh Mishra
Reyansh Mishra

Reputation: 1915

If I understood your question correctly Please try this code and let me know if it doesn't work

Adapter Java Code

public class Adapter extends RecyclerView.Adapter<Adapter.ItemHolder> {

    private ArrayList<DemoData> mDemoData;

    public Adapter() {
        mDemoData = new ArrayList<>();
        for (int i = 0; i <= 100; i++) {
            mDemoData.add(new DemoData("Item " + i, false));
        }
    }

    @Override
    public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ItemHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recyler_card, parent, false));
    }

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

        //Check if the item is check and toggle the checkbox
        if (mDemoData.get(position).checked) {
            holder.mCheckBox.setChecked(true);
        } else {
            holder.mCheckBox.setChecked(false);
        }

        //Set text to the textview
        holder.mTextView.setText(mDemoData.get(position).item);

    }

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

    public class ItemHolder extends RecyclerView.ViewHolder {
        private TextView mTextView;
        private CheckBox mCheckBox;

        public ItemHolder(View itemView) {
            super(itemView);
            mTextView = (TextView) itemView.findViewById(R.id.textView);
            mCheckBox = (CheckBox) itemView.findViewById(R.id.checkbox);

            //set OnClickListener 
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mCheckBox.getContext(), "Clicked", Toast.LENGTH_SHORT).show();
                }
            });

            //set OnLongClickListener
            itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    //if handled return true if not return false;
                    Toast.makeText(mCheckBox.getContext(), "Long Clicked", Toast.LENGTH_SHORT).show();
                    return false;
                }
            });

            mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    mDemoData.get(getAdapterPosition()).checked = isChecked;
                }
            });
        }
    }
}

ItemView XML Code

<?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="75dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="75dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <CheckBox
            android:id="@+id/checkbox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</android.support.v7.widget.CardView>

Activity Java Code

public class RecyclerDemoActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_demo);
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
        mRecyclerView.setAdapter(new Adapter());
    }
}

Just use this demo and change your code accordingly.

Edit: This is the model class which is used.

 public class DemoData{
    public String item;
    public boolean checked;
    public DemoData(String item,boolean isChecked){
    this.item=item;
    this.checked=isChecked;
    }
    }

|REY|

Upvotes: 0

Malik
Malik

Reputation: 5043

try this

public class MyRecylerAdapter extends RecyclerView.Adapter<MyRecylerAdapter.ItemHolder> {

...

    public MyRecylerAdapter(Context context, ArrayList<ListItem> listItems,
                            ArrayList<ListItem> selectedList) {
        this.mContext = context;
        this.mListItems = listItems;
        this.selectedItemsList = selectedList;
    }

    private int selectedPos = -1;

    public class ItemHolder extends RecyclerView.ViewHolder {

        private CardView cardView;
        private CheckBox chkSelected;

        private ItemHolder(final View itemView) {
            super(itemView);

            cardView = (CardView) itemView.findViewById(R.id.singlecard_view1);
            chkSelected = (CheckBox) itemView.findViewById(R.id.chkSelected);
        }

        void bind(int position) {

            if (checkedListItems.contains(position)) {
                chkSelected.setChecked(true);
            } else {
                chkSelected.setChecked(false);
            }
        }
    }

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

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false);
        final ItemHolder itemHolder = new ItemHolder(view);

        return itemHolder;
    }

    public void onBindViewHolder(final ItemHolder itemHolder, final int position) {

        final ListItem listItem = mListItems.get(position);

        itemHolder.bind(position);

        if (checkedListItems.contains(position)) {
            itemHolder.cardView.setActivated(true);
        } else {
            itemHolder.cardView.setActivated(false);
        }

        if (itemHolder.getAdapterPosition() == selectedPos) {
            itemHolder.cardView.setActivated(true);
        } else {
            itemHolder.cardView.setActivated(false);
        }

        itemHolder.itemView.setOnClickListener(new View.OnClickListener() {
            // Handles the row being clicked.
            @Override
            public void onClick(View view) {

                if (recyclerItemClickListener != null) {
                     recyclerItemClickListener.onItemClick(itemHolder.itemView, listItem);
               }
           }
       });

       itemHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
           @Override
           public boolean onLongClick(View view) {

               if (recyclerItemClickListener != null) {
                   recyclerItemClickListener.onItemLongClick(itemHolder.itemView, listItem);
               }

               int adapterPos2 = itemHolder.getAdapterPosition();
               if (adapterPos2 != android.support.v7.widget.RecyclerView.NO_POSITION) {
                   int lastSelectedPosition = selectedPos;
                   selectedPos = adapterPos2;
                   notifyItemChanged(lastSelectedPosition);
                   notifyItemChanged(selectedPos);
               }
               return true;
           }
       });

       itemHolder.chkSelected.setOnClickListener(new View.OnClickListener() {
        @Override
           public void onClick(View v) {

               if (position == android.support.v7.widget.RecyclerView.NO_POSITION) return;
               if (recyclerItemClickListener != null) {
                   recyclerItemClickListener.onCheckBoxClick(v, position);
               }
               Integer iPos = position;

               if (((CheckBox) v).isChecked()) {
                   checkedListItems.add(iPos);
               } else {
                   checkedListItems.remove(iPos);
               }
           }
       });
   }

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

Upvotes: 0

Related Questions