Out of the recyclerview item, I need to select only one and make its background white and deselect the previous one.
public class viewHolder extends RecyclerView.ViewHolder {
TextView periodCategoryName;
ImageView periodCategoryPhoto;
View dottedLine;
public viewHolder(View itemView) {
super(itemView);
periodCategoryPhoto=(ImageView) itemView.findViewById(R.id.mood_icon);
periodCategoryPhoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Get Adapeter position ",Integer.toString(getAdapterPosition()));
selectedPosition=getAdapterPosition();
notifyItemRangeChanged(0,periodListPhoto.size()-1);
}
});
}
}
#Override
public void onBindViewHolder(final PeriodListAdaptor.viewHolder holder, final int position) {
holder.periodCategoryPhoto.setImageResource(periodListPhoto.get(position));
//only one period item is highlighted
if(selectedPosition == position){
//already selected item
Log.i("Selected position is ",Integer.toString(selectedPosition));
holder.periodCategoryPhoto.setBackground(ContextCompat.getDrawable(mContext,R.drawable.item_selected));
}else{
//do nothing
}
}
I am getting the strange behavior. Sometimes previously selected item is deselected upon selecting a new item. Sometimes both are selected.
ViewHolders are being reused, which means that you should take care of handling both cases in your onBindViewHolder():
if (selectedPosition == position) {
...
} else {
holder.periodCategoryPhoto.setBackground(defaultBagroundColor);
}
Related
I have a recycler view on one tab. I am trying to move the recyclerview to the next tab when the user clicks on the next button as shown below. Im having to add the code move on the adapter class. Hence, below is the code for the adapter class. Any idea on how to move the recyclerview to the next tabs (ongoing + finished)
code
public class recyclerKanbanAdapter extends RecyclerView.Adapter<recyclerKanbanAdapter.MyViewHolder> {
ArrayList<kanbanItems> kanlist;
Context context;
public recyclerKanbanAdapter(Context context,ArrayList<kanbanItems>kanbanList)
{
this.context=context;
this.kanlist=kanbanList;
}
public recyclerKanbanAdapter.MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.fragment_itemkanban,parent,false);
return new recyclerKanbanAdapter.MyViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull recyclerKanbanAdapter.MyViewHolder holder, int position) {
kanbanItems kanban = kanlist.get(position);
holder.contractorName.setText(kanban.getContractorName());
holder.Duration.setText(kanban.getDuration());
holder.taskName.setText(kanban.getTaskName());
holder.btn_Delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
kanlist.remove(holder.getAdapterPosition());
notifyItemRemoved(holder.getAdapterPosition());
notifyItemRangeChanged(holder.getAdapterPosition(), kanlist.size());
}
});
holder.btn_Move.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//struggling to implemene the move button
}
});
}
#Override
public int getItemCount() {
return kanlist.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder{
EditText taskName,Duration,contractorName;
ImageButton btn_Delete;
ImageButton btn_Move;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
btn_Move=itemView.findViewById(R.id.btn_move);
btn_Delete=itemView.findViewById(R.id.btn_delete);
taskName= itemView.findViewById(R.id.txtTaskName);
Duration=itemView.findViewById(R.id.txtDuration);
contractorName=itemView.findViewById(R.id.txtContractor);
}
}
}
I have a RecyclerView in my activity and I want to add Multiple selection to the RecyclerView, and this is my Adapter:
public class RingtoneItemAdabter extends RecyclerView.Adapter<RingtoneItemAdabter.ViewHolder> {
private Context context;
private Activity activity;
private List<RingtoneItem> list;
private boolean selectionMode = false;
private List<RingtoneItem> selectedItems = new ArrayList<>();
public class ViewHolder extends RecyclerView.ViewHolder {
public Switch aSwitch;
public TextView textView;
public View view;
public CheckBox checkBox;
public ViewHolder(View view) {
super(view);
this.view = view;
aSwitch = (Switch) view.findViewById(R.id.ringtone_state_switch);
textView = (TextView) view.findViewById(R.id.ringtone_title_textview);
checkBox = (CheckBox) view.findViewById(R.id.selection_checkbox);
}
}
public RingtoneItemAdabter(Context context, Activity activity, List<RingtoneItem> list) {
this.context = context;
this.activity = activity;
this.list = list;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.recyclerview_item, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final RingtoneItem item = list.get(position);
holder.checkBox.setVisibility(selectionMode ? View.VISIBLE : View.GONE);
holder.textView.setText(item.getTitle());
holder.aSwitch.setChecked(item.isActive());
holder.textView.setTextColor(item.isActive() ? Color.BLACK : Color.GRAY);
holder.aSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
holder.textView.setTextColor(Color.BLACK);
item.setActive(true);
writeToFile();
} else {
holder.textView.setTextColor(Color.GRAY);
item.setActive(false);
writeToFile();
}
}
});
holder.view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if(selectionMode){
return false;
}else {
startSelecting();
holder.checkBox.setChecked(true);
return true;
}
}
});
holder.view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(selectionMode){
holder.checkBox.setChecked(!holder.checkBox.isChecked());
}
}
});
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){
selectedItems.add(item);
}else {
selectedItems.remove(item);
}
if(selectedItems.size() == 0){
stopSelecting();
}
}
});
}
#Override
public int getItemCount() { ... }
private void writeToFile() { ... }
private void startSelecting(){
selectionMode = true;
notifyDataSetChanged();
}
private void stopSelecting(){
selectionMode = false;
notifyDataSetChanged();
}
}
and this is the checkbox tag in recyclerview_item:
<CheckBox
android:id="#+id/selection_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
so I want the startSelection method to show the checkbox in every item, and the stopSelection method to hide the checkbox in every item.
EDIT:
It's looks like I got a problem, the problem is now when I click and hold on an item the checkboxes appear and the checkbox of the item I long clicked must get checked, and if I unchecked every box, the checkboxed should disappear,this is how the app should work, but the when I tried it, it's didn't work, when I long click an item the checkboxes appear in some cases another checkbox get checked, but in another cases no one of the checkboxes get checked, and when I uncheck every checkbox, the checkboxes stay there.
I have an idea about why the checkboxed don't disappear, because for example if I long clicked the fourth item, the checkboxes will appear, but rather than the fourth item which should get checked the first item will get checked, but the fourth item is the one which will added to selectedItems list, so if I unchecked the first box nothing will happen because it's not stored in the list, but if I checked the fourth item, then another fourth item will added to the list, and if I unchecked it, one of the two copies of the fourth item will removed, but one will stay.
check the code above.
I know my explain is very bad, and my English isn't very good, but hope you understand :)
Define a boolean variable for show/hide checkbox state and in onBindViewHolder set visibility of your checkbox related to that variable
boolean showCheckboxes = false;
public void startSelection() {
showCheckboxes = true;
notifyDataSetChanged();
}
public void stopSelection() {
showCheckboxes = false;
notifyDataSetChanged();
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final RingtoneItem item = list.get(position);
holder.checkBox.setVisibility(showCheckboxes ? View.VISIBLE: View.GONE);
/*
...
*/
}
I am using recyclerView to build a list of toggle buttons (like a numpad), I would like to achieve:
when user 'turns on' a button by clicking it, 'turns off' all other buttons
I have tried to add an onClickListener inside the view holder class, and call notifyDataSetChanged() such that onBindViewHolder(final ViewHolder holder, int position) is called and then change the state of the button.
But it doesn't work, the button clicked does not change its state.
ViewHolder
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
ToggleButton button;
String id;
public ViewHolder(View itemView) {
super(itemView);
button = (ToggleButton) itemView.findViewById(R.id.toggle);
button.setOnclickListener(this);
}
#Override
public void onClick(View view) {
((ToggleButton) view).setChecked(true);
int pos = getAdapterPosition();
if (pos != RecyclerView.NO_POSITION) {
selected = pos; //store the position of the user clicked button
notifyDataSetChanged();
}
}
onBindViewHolder() in my adpater class
public void onBindViewHolder(final ViewHolder holder, int position) {
String data = mData.get(position);
holder.id = data;
holder.button.setText(data);
holder.button.setTextOn(data);
holder.button.setTextOff(data);
if (position != selected) { //if the button is not the user chosen one
if (holder.button.isChecked()) { // and it's in 'ON' state
holder.button.toggle(); // toggle it to switch 'OFF'
}
}
There are a couple of things you are doing incorrectly. The ViewHolder should contain only views and not click handlers or strings etc. (The clue is in the name). You add the handlers and manipulate the views when you bind the ViewHolder to your data class.
From what I can determine, you want a simple list of toggle buttons. When one button is on, the others should turn off. The test adapter I created for you below demonstrates that.
Ideally, you would avoid notifyDataSetChanged and use the row based versions but as each time the toggle is pressed, it affects every other row, you do not really have a choice in this use case unless you keep track of the selected row.
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.VH> {
public static class MyData {
public boolean Selected = false;
public String Text;
public MyData(String text) {
Text = text;
}
}
public List<MyData> items = new ArrayList<>();
public TestAdapter() {
this.items.add(new MyData("Item 1"));
this.items.add(new MyData("Item 2"));
this.items.add(new MyData("Item 3"));
}
#Override
public TestAdapter.VH onCreateViewHolder(ViewGroup parent, int viewType) {
return new VH((
LayoutInflater.from(parent.getContext())
.inflate(R.layout.test_layout, parent, false))
);
}
#Override
public void onBindViewHolder(TestAdapter.VH holder, int position) {
final MyData itm = items.get(position);
holder.button.setChecked(itm.Selected);
holder.text.setText(itm.Text);
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
for (MyData x: items){
x.Selected=false;
}
itm.Selected = true;
notifyDataSetChanged();
}
});
}
#Override
public int getItemCount() {
return items.size();
}
public class VH extends RecyclerView.ViewHolder {
ToggleButton button;
TextView text;
public VH(View itemView) {
super(itemView);
button = itemView.findViewById(R.id.toggle);
text = itemView.findViewById(R.id.text1);
}
}
}
test_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ToggleButton
android:id="#+id/toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Try setting OnCheckedChangeListener instead of 'OnclickListener`
`button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// The toggle is enabled
} else {
// The toggle is disabled
}
}
});`
Android Doc : https://developer.android.com/guide/topics/ui/controls/togglebutton.html
set on click listener in the onBindView and In the onClick method,
first "turn off" all the toggle button by setting a parameter in the list model
and then "turn on" the selected one if it is not selected.
#Override
public void onClick(View view) {
// clear all model values to isSelected false in the list
}
I had the following holder that worked, i.e. I was able to check/uncheck the checkbox. (The checkbox is part of the RecyclerView card):
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.bindData(numbers.get(position));
//in some cases, it will prevent unwanted situations
holder.checkbox.setOnCheckedChangeListener(null);
//if true, your checkbox will be selected, else unselected
holder.checkbox.setChecked(numbers.get(position).isSelected());
holder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
numbers.get(holder.getAdapterPosition()).setSelected(isChecked);
}
});
}
I wanted to implement click of the item on RecyclerView. So, I took from this solution - please check: https://stackoverflow.com/a/26196831/4013399
However, now, the click of the entire card item works, but the checkbox can not be checked/unchecked. How to solve this?
Please help. Thanks.
Update
I made changes - however, "HERE-1,2 and 3" lines are never entered.
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Log.e("I AM ", "HERE-0");
holder.bindData(numbers.get(position));
final RelativeLayout rlyItem = holder.rlyItem;
final CheckBox checkbox = holder.checkbox;
rlyItem.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
mListener.onItemClicked(holder.getLayoutPosition());
Log.e("I AM ", "HERE-1");
}
});
checkbox.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
if (((CheckBox) view).isChecked()) {
checkbox.setChecked(false);
Log.e("I AM ", "HERE-2");
} else {
checkbox.setChecked(true);
Log.e("I AM ", "HERE-3");
}
// Inform to Activity or the Fragment where the RecyclerView reside.
mListener.onItemCheckBoxChecked(((CheckBox) view).isChecked(), holder.getLayoutPosition());
}
});
//in some cases, it will prevent unwanted situations
holder.checkbox.setOnCheckedChangeListener(null);
//if true, your checkbox will be selected, else unselected
holder.checkbox.setChecked(numbers.get(position).isSelected());
checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
numbers.get(holder.getAdapterPosition()).setSelected(isChecked);
Log.e("I AM ", "HERE-4");
//Log.e(Integer.toString(holder.getAdapterPosition()), " IS CHECKED");
}
});
}
Simply call performClick() for your checkbox on click of your adapter inflated view in adapter class.
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.checkbox.performClick();
}
});
First You add the below property in your checkbox
android:clickable="false"
android:focusable="false"
android:longClickable="false"
Below is my itemclick
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Utils.hideSoftKeyboard(getActivity());
cityAdapter.itemSelected(position);
}
}));
Add below method in your adapter :
public void itemSelected(final int position) {
if (townModelArrayList != null && !townModelArrayList.isEmpty()) {
townModelArrayList.get(position).setSelected(!townModelArrayList.get(position).isSelected());
notifyDataSetChanged();
}
}
I wrote a library to handle android recycler view item click event. You can find whole tutorial in https://github.com/ChathuraHettiarachchi/RecycleClick
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
#Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
}
});
or to handle item long press you can use
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemLongClickListener(new RecycleClick.OnItemLongClickListener() {
#Override
public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
return true;
}
});
to handle checkbox click you need to setCheckChangeListner on your adapter
I solved this problem by removing the whole class referenced in the question link (https://stackoverflow.com/a/26196831/4013399). Instead I implemented an onClick listener only for the checkbox. And for the whole card view item click?, you may ask. For that, I simply implemented another onClick listener for a layout that contained my textbox.
Also, to save the state of the checkboxes a simple setting and getting of key,value pairs like (checkbox position, "1") (where 1 indicates checked) and simultaneously updating this in the SharedPreferences worked.
TL; DR
To implement RecyclerView item click and a clickable view in RecyclerView item, You need to define listener for each of them.
First, you need to define the layout:
<?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"
>
<RelativeLayout
android:id="#+id/item__rly"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:selectableItemBackground"
android:clickable="true"
>
<CheckBox
android:id="#+id/item_cbx"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sample CheckBox" />
</RelativeLayout>
</android.support.v7.widget.CardView>
From the above xml code, you can find that the RelativeLayout using:
android:background="?android:selectableItemBackground"
android:clickable="true"
This is to make the item having an animation when clicked.
Second, you need to define click listener interface within your Adapter, something like this:
public class YourAdapter extends
RecyclerView.Adapter<YourAdapter.ViewHolder> {
private List<YourData> mDatas;
// Define listener member variable
private static OnRecyclerViewItemClickListener mListener;
// Define the listener interface
public interface OnRecyclerViewItemClickListener {
void onItemClicked(int position);
void onItemCheckBoxChecked(boolean isChecked, int position);
}
// Define the method that allows the parent activity or fragment to define the listener.
public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener listener) {
this.mListener = listener;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
RelativeLayout rlyItem;
CheckBox cbxSample;
// We also create a constructor that accepts the entire item row
// and does the view lookups to find each subview
public ViewHolder(View itemView) {
// Stores the itemView in a public final member variable that can be used
// to access the context from any ViewHolder instance.
super(itemView);
rlyItem = (RelativeLayout) itemView.findViewById(R.id.item__rly);
cbxSample = (CheckBox) itemView.findViewById(R.id.item_cbx);
}
}
// Usually involves inflating a layout from XML and returning the holder
#Override public ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate the custom layout
View viewHolder = inflater.inflate(R.layout.item_layout, parent, false);
// Return a new holder instance
return new ViewHolder(viewHolder);
}
// Involves populating data into the item through holder
#Override public void onBindViewHolder(final ViewHolder viewHolder, int position) {
// Get the data model based on position
final YourData data = mDatas.get(position);
final RelativeLayout rlyItem = viewHolder.rlyItem;
CheckBox cbxSample = viewHolder.cbxSample;
rlyItem.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
mListener.onItemClicked(viewHolder.getLayoutPosition());
}
});
cbxSample.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
if (((CheckBox) v).isChecked()) {
cbxSample.setChecked(false);
} else {
cbxSample.setChecked(true);
}
// Inform to Activity or the Fragment where the RecyclerView reside.
mListener.onItemCheckBoxChecked(((CheckBox) v).isChecked(), viewHolder.getLayoutPosition());
}
});
}
#Override public int getItemCount() {
return mDatas.size();
}
Then, in your Activity or Fragment where RecyclerView code reside, you need to set the listener:
yourAdapter.setOnRecyclerViewItemClickListener(new YourAdapter.OnRecyclerViewItemClickListener() {
#Override
public void onItemClicked(int position) {
// Do something when item clicked.
}
#Override
public void onItemCheckBoxChecked(boolean isChecked, int position) {
// Do something when check box check state change.
}
});
Addition:
To hold the the state of item in your ReyclerView, you need to use SparseBooleanArray
I have a recyclerView behanving like a list, how do I change the background color of only one view? The item I want to change the color's ID is "1", I thought about getting it in the activity by it's ID and add it a decorator, but I don't know how to, or if it's even possible.
Inside the adapter:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setEventNameName(i + "");
holder.settheColor(Color.parseColor("#000000"));
}
static int i;
class ViewHolder extends RecyclerView.ViewHolder{
public TextView eventName;
public RelativeLayout theLayout;
public ViewHolder(final View itemView) {
super(itemView);
eventName = (TextView)itemView.findViewById(R.id.eventName);
theLayout = (RelativeLayout)itemView.findViewById(R.id.backgroundevent);
theLayout.setId(++i);
theLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getAdapterPosition()>0){
removeItem(getAdapterPosition());
}else {
addItem("");
}
}
});
}
public void settheColor(int theColor){
theLayout.setBackgroundColor(Color.parseColor(String.valueOf(theColor)));
}
public void setEventNameName(String TheEventName){
eventName.setText(TheEventName);
}
}
I feel you can do it in this way --
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
currentListItem = List.get(position);
if(position == 0) //this will let you know the first child item
{
holder.textview.setBackgroundColor(Color.RED);
}
}
Hope this helps!
Pretty simple, use the onBindViewHolder method of your adapter, and change the color of the view (which should be referenced in your ViewHolder)
Follow this example if you are new to the Recyclerview concept.