Add selected position in RecyclerView to a set and highlight those position - android

I have a recyclerView and have implemented onLongClick listener on the items. The Adapter is in the same class as the Activity.
I created a set: public Set<Integer> multiplePositions as instance variable of the Activity class and am initialising it in onCreate() method as multiplePositions = new TreeSet<>().Coming to my Adapter class in the onBindViewHolder method I created a click listener as follows:
holder.textCardView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Adapter.this.onLongClick(holder, position);
return true;
}
});
holder.textCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
As you can see I am calling the method onLongClick. My onLongClick method looks like this:
public void onLongClick(ViewHolder holder, int position) {
multiplePositions.add(position);
for(Integer i : multiplePositions) {
Log.e("set", ""+i);
}
holder.textCardView.setBackgroundResource(R.color.long_press);
}
Here, whenever an item clicked I am adding the position in the Set but I don't know how do I iterate through this set and set the background color of all the item at the positions in the set.
I am aware that this can be achieved by creating a boolean variable isSelected in the model class but if I go with this method then other functionalities of my code won't work.
My main concern is if I scroll the recyclerView up or down then color of the selected positions should not disappear. The unselection part will be done in setOnClickListener().

Use SparseBoolean array to store the positions of the items clicked in the reyclerview.Check the answer in this link
https://stackoverflow.com/questions/46336645/hilighted-selected-items-colour-changes-when-not-in-view-in-recyclerview/46336844#46336844
Check here the purpose of using SparseBoolean array
https://stackoverflow.com/questions/18822708/what-is-the-clear-purpose-of-sparsebooleanarray-i-referred-official-android
EDIT:
Use SparseBooleanArray to keep track of selected items in recycler view adapter
Initialize the SparseBooleanArray as private memeber variable
private SparseBooleanArray mClickedItems=new SparseBooleanArray();
Inside your click function while clicking textCardView make the item position as true.
holder.textCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mClickedItems.put(position,true);
notifyDataSetChanged();
}
});
Then in the onBindViewHolder check if the position is already selected or not like this
if(mClickedItems.get(position)==true){
//Show selected color
holder.textCardView.setBackgroundResource(ContextCompat.getColor(holder.textCardView.getContext(),R.drawable.selected));
}else {
//show unselected color
holder.textCardView.setBackgroundResource(ContextCompat.getColor(holder.textCardView.getContext(),R.drawable.unselected));
}

Related

Update TextView in Fragment when RecyclerView's data changes

In my Fragment, I have 2 views. A Textview and a RecyclerView. The Textview essentially displays the current size of the RecyclerView. So, when a row is removed in the adapter class, I need to update the TextView's value accordingly.
The row is removed successfully when removeBtn is clicked, but I need to update the TextView in the Fragment accordingly.
FRAGMENT
titleText.text = "SIZE (" + arrayStringList().size.toString() + ")"
//...
//...
//Set RecyclerView Adapter
mRecyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context)
val adapter = MRecyclerView(context!!, arrayStringList)
mRecyclerView.adapter = adapter
RECYCLERVIEW
holder.removeBtn{
mData.removeAt(position)
notifyItemRemoved(position)
}
Is there some sort of listener that I can put in my fragment to detect when the data changes? Or is there a way to send data from the recyclerview back to the fragment when removeBtn is clicked?
Create a interface in recyclerView class , and implement that interface in fragment . Once you click the remove button , call this interface . In Fragment class , update the text view with adapter.getItemCount.
In Adapter
interface ItemCallback{
void updateTextView();
}
This interface will be implemented in fragment class ,where you can update your textView with itemCount .
public class Fragment implements Adapter.ItemCallback{
#Override
public void updateTextView() {
tvTextView.setText(adapter.getItemCount()); // This will return the current item count of adapter
}
}
You can do this via call back. Make an interface and implement that on Fragment. And pass the reference of the interface to the adapter. When you trigger the event to delete item from recycler view call the interface method (That you implemented on Activity). And in that call back method, you need to set the value to your text view. To set value on TextView, you can call size() method and set the value whatever is returned from it. For example the List you are passing to the adapter is mData. When you get call back the call size method on the reference and set the value as mentioned below code.
titleText.setText(String.valueOf(mData.size())).
Hope this will help you.
NOTE: You need to call String.valueOf method because size method returns integer value so it needs to be cast.
"Or is there a way to send data from the recyclerview back to the fragment when removeBtn is clicked?" the answer is yes
One approach is to pass your adapter your own click listener (an interface), this way you can control the click from the fragment something like this,
A1) create an interface
public interface ItemTouchListener {
void onCardClick(View view, int position);
boolean onCardLongClick(View view, int position);
}
A2) implement this interface in your fragment
public class YourFragment extends Fragment implements ItemTouchListener
A3) implement the methods you created in your fragment
#Override
public void onCardClick(View view, int position) {
if (view.getId() == R.id.removeBtn){
//update your text
}else{
//other buttons
}
}
#Override
public boolean onCardLongClick(View view, int position) {
if (view.getId() == R.id.removeBtn){
//update your text
} else {
//other buttons
}
return true;
}
A4) create this interface in your adapter and set it to your button
private ItemTouchListener onItemTouchListener;
public YourAdapter(List<Object> list, ItemTouchListener onItemTouchListener) {
this.onItemTouchListener = onItemTouchListener;
this.list = list;
}
removeBtn = view.findViewById(R.id.removeBtn);
removeBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onItemTouchListener.onCardClick(v, getAdapterPosition());
}
});
removeBtn.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
onItemTouchListener.onCardLongClick(view, getAdapterPosition());
return true;
}
});
A5) and now when you create your adapter it will ask for the ItemTouchListener which you can give it by just passing 'this'
YourAdapter adapter = new YourAdapter(this);
A6) you may also want to give your adapter a method something like getCount which return the list size
public int getCount(){
list.size();
}
and then you can call this like myAdapter.getCount

how to hide an item in list by clicking another item of the same list in recycler view?

I have a list of elements in recycler view, my need is to hide some elements by clicking a specific element of the same list. For instance, my list contains 10 elements and I want to hide all the elements from position 6 by clicking the element in the 5th position. how can I do that?
You have to remove that element from dataset and call notifyOnDataSetChanged Method, otherwise you can create a model class with boolean/hide show flag and then on item click listener you can set flag accordingly to remove/hide element.
Recyclerview react to notifyDatasetChanged method to redraw each visible row.
try to change behind model of recycler view then notifyDatasetChanged
bindViewHolder(VH holder, int position){
view.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
// Do you business to change data model in other position which
//identified whether the view must be visible or not
notifyDataSetChanged();
}
});
}
Just try this...
public void onBindViewHolder(final ViewHolder viewHolder,
final int position) {
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// set your logic like this..
if(position==5){
if(list.size()>6){
list.remove(6); // here list will be your data list.
notifyDataSetChanged();
}
}
}
});

Delete edittext value in the recyclerview

Currently: i have a recycler view where it has delete button and an edit text for each item.
Each item in the recycler view contains edit text that the user can input.
The scenario is i have 4 item in the list resulting 4 edit text.
When i try to fill up edit Text in the item(n) and tried to delete
the item(n) and add again. The edit Text value in the edit text remains.
How can i clear the value of the edit text?
Here is my current code when i try to delete a specific item in the list:
mHeaderText.remove(pos);
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int i = 1 ; mHeaderText.size() >= i ; i++) {
temp.add(i);
Log.d("ADDDING","ADDDING"+i);
}
mHeaderText.clear();
mHeaderText.addAll(temp);
notifyDataSetChanged();
Try this code ..
In adapter class in onBindView method when you perform click event then set edittext value as null.
edittext.setText("");
and if your edittext box in activity layout then make interface into adapter class and handling click event like this way...
OnItemClick onItemClick;
public void setOnItemClick(OnItemClick onItemClick) {
this.onItemClick = onItemClick;
}
public interface OnItemClick {
void getPosition(String data); //pass any data to shared it.
}
after that..
#Override
public void onBindViewHolder(ItemViewHolder holder, final int position) {
// below code handle click event on recycler view item.
final String data = mStringList.get(position);
holder.textView.setText(data);
holder.firstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onItemClick.getPosition(data); // shared data.
}
});
}
after that in activity adapter bind into recycler view it means adapter not null then called below line..
adpater.setOnItemClick(new RecyclerViewAdpater.OnItemClick() {
#Override
public void getPosition(String data) {
// hear perform any operation.
editTextbox.setText("");
adpater.notifyDataSetChanged();
}
});
Use
edittext.setText("");
to clear text where edittext is reference to EditText. Since you haven;t posted complete code so i can guide to this only. If you provide more code, then I can help you more.
One thing is sure. You will need to use
edittext.setText("") to clear the value.
But you need to be careful. You need to keep this as the first line in your delete row function, i.e. before you are removing that edittext item from your list.
Here is my code: I have placed the "remove row" function inside onBindViewHolder() method of Recyclerview Adapter.
holder.delImgView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// You need to place it in the start
holder.editText.setText("");
// Remove the item on remove/button click
myArrayList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, myArrayList.size());
Toast.makeText(context, "Removed : " + position +" item", Toast.LENGTH_SHORT).show();
}
});

RecyclerView changes multiple rows although only one row was targeted

I got a RecyclerView and want to change the appearance of any clicked row. For that I have a callbackFunction in my Activity which I pass to the Adapter, which then is called inside the Adapter, as soon as I click on any row in the RecyclerView.
The clicked row is then changed, but it happens, that not only the clicked rows are changed but also other rows, that weren't clicked and were never clicked before. I checked the ArrayList that contains the data, but everything is fine there. Only the clicked elements contain the trigger to change the appearance of the row.
What is causing the other rows to change, although they have not been clicked?
Interface inside activity for callback
public interface onHeaderClickListener{
void onHeaderClicked(int index);
}
Inside RecyclerView Adapter
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof ViewHolderHeader){
((ViewHolderHeader)holder).dateHeaderTextView.setText( Integer.toString(((objClass_offerDateHeader) arrayList.get(position)).getDate()));
if(((objClass_offerDateHeader) arrayList.get(position)).isSelected()){
((ViewHolderHeader)holder).dateHeaderTextView.setBackgroundColor(Color.parseColor("#b642f4"));
}
((ViewHolderHeader)holder).dateHeaderTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onHeaderClickListener.onHeaderClicked(position);
}
});
}
}
Adapter initialisation inside activity
customAdapterRecyclerViewAddOffersTo = new customAdapterRecyclerViewAddOffers(offerArrayList,"dragTo", new onHeaderClickListener() {
#Override
public void onHeaderClicked(int index) {
if (offerArrayList.get(index) instanceof objClass_offerDateHeader){
if(((objClass_offerDateHeader) offerArrayList.get(index)).isSelected()){
((objClass_offerDateHeader) offerArrayList.get(index)).setSelected(false);
}
else {
((objClass_offerDateHeader) offerArrayList.get(index)).setSelected(true);
}
customAdapterRecyclerViewAddOffersTo.notifyDataSetChanged();
}
}
});
In your onBindViewHolder method you have to set the background of the unselected cell, keep in mind the the cells are reused and you only set the background of selected cells so when it is reused the background is not returned to the normal color
So in code you will have to add an else condition
if(((objClass_offerDateHeader) arrayList.get(position)).isSelected()){
((ViewHolderHeader)holder).dateHeaderTextView.setBackgroundColor(Color.parseColor("#b642f4"));
} else {
((ViewHolderHeader)holder).dateHeaderTextView.setBackgroundColor(Color.parseColor("#FFFFFF")); // I assume you need it to be white you can change it to any other color
}
You need to add an else condition here:
if(((objClass_offerDateHeader) arrayList.get(position)).isSelected()){
((ViewHolderHeader)holder).dateHeaderTextView.setBackgroundColor(Color.parseColor("#b642f4"));
}
Viewholders get recycled, so you cannot be sure of the current state when onBindViewHolder is called.

Keep listview item selected even if view changes

I have a listview in fragment.
When I select a listview item, it gets highlighted and then I open another fragment.
Now, what I want is, when I move back to previous fragment, the list item should stay selected.
How can I do that?
I have implemented like
add this two methods in your Adapter
private int selectedIndex = ListView.NO_ID;
public int getSelectedIndex() {
return selectedIndex;
}
public void setSelectedIndex(int index) {
this.selectedIndex = index;
// Re-draw the list by informing the view of the changes
notifyDataSetChanged();
}
and in your Adapter getView(...) do
// Highlight the selected item in the list
if (selectedIndex != -1 && selectedIndex == position) {
YourView.setBackgroundResource(R.color.lightred);
}
and implement in Fragment in setOnItemClickListener onItemClick(...) like
adapter.setSelectedIndex(position);
save this selected value in some preferences and when you come back again call in Fragment on resume(...)
adapter.setSelectedIndex(selectedIndex);
OK let's do this
declare one field in your adapter say
private int selectedPosition=-1;
now create a setter for this
private void setSelectedPosition(int position)
{
selectedPosition=position;
}
Now in your getView method
if(position==selectedPosition)
{
listItemView.setSelected(true);
//OR
listItemView.setBackgroundColor(<Some Color>);
}
Now after setting the adapter when user tap and your OnItmeSelected called
adapter.setSelectedPosition(<your desired selected item position>);
adapter.notifyDataSetChanged();

Categories

Resources