I am implemeting multiple selection on GridManager using RecyclerView.
Here is my code inside adapter
imgStamps.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
//First setting up isSelected() or not
if (imageList.get(getAdapterPosition()).isSelected()) {
imageList.get(getAdapterPosition()).setSelected(false);
} else {
imageList.get(getAdapterPosition()).setSelected(true);
}
//Setting blur image on Imageview onLongclick and resting on again press.
if (imageList.get(getAdapterPosition()).isSelected()) {
mCount++;
imgBlurr.setVisibility(View.VISIBLE);
} else {
mCount--;
imgBlurr.setVisibility(View.GONE);
}
mCommunicator.clicked(mCount, getAdapterPosition());
return true;
}
});
The above code is inside ViewHolder not onBindViewHolder.
If I am selectimg first image and scrolls down and then up the view gets reset.
Can the mistake or behaviour can be pointed out?
RecyclerView reuses your layout. Put your logic on onBindViewHolder method.
For more information explore this question
How to properly highlight selected item on RecyclerView?
RecyclerView will reused your item view when you scroll. To manager multi select you must have an array of selected position (or selected model). And onBindViewHolder, check position in this array to check item selected or not. For more details implement, please refer to : Multi selection in RecyclerView?
Related
I have a RecyclerView to list a set of data. And on clicking each item , I have validation to check previous item is entered or not. If that item is not entered I want to enable an inline error (which is hidden in normal case) message in the previous row. I have done the scenario as shown below but error is showing only in the current row. Anyone suggest how I can enable/update previous row or a specific row.
public boolean _validateListItems(int itemIndex)
{
int previousItemIndex = itemIndex - 1;
for (int i = 0; i <= previousItemIndex; i++)
{
if ((listRecyclerItem.get(i).getEnable()==0))
{
return false;
}
}
return true;
}
holder.expand_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(position>0){
if(_validateListItems(position))
{
mExpandedPosition = isExpanded ? -1:position;
notifyItemChanged(previousExpandedPosition);
notifyItemChanged(position);
notifyDataSetChanged();
}
else
{
holder.error.setVisibility(View.VISIBLE);
holder.error.setTextColor(ContextCompat.getColor(context, R.color.error_red));
}
}
}
});
First of all RecyclerView is something that recycle view. View is generated is based on Data Model.
So, lets store the user button/checkbox click/checked action) to the respective Model/Item. To run the validation, get the items from the Adapter and check your conditions in Activity/Fragment [Looping is an expensive operation, use Coroutine or RxJava]. Execute your validation and if Validation is true for an item, just update the Item from the list and finally update the Adapter. You can pass the Error message in the item and render it to the View. And finally, must use DiffUtil to update the items in adapter.
Declare an interface for your adapter that has callback to your viewModel and when each item changed you can return the call back ito viewmodel and store it in an object or array
for example :
interface Callback { void onDataChanged(int itemPosition); }
call that method in onBindViewHolder when your item text changed
and in view model add the returned item into a list
when you clicked on a button, you can check the items if your necessary item didn't exist you can return error
I use FirestoreRecyclerAdapter in which i want change selected item color. because in firestoreAdapter it comes to onBindViewHolder() only item data change.for single item replace it ,but i want to change all item text color to which except selected item.
how can i do ?
thanks.
Reverse your logic then. Declare a list that keeps the clicked item (store the index, id or whatever you prefer), then in your onBindViewHolder(), do nothing if the clicked item is in that list, else change whatever you want.
Of course, you must update this list if you allow insertion/removal/change in your list.
EDIT
To answer your questions in your comments, first you must design the logic to change the color accordingly in onBindViewHolder(). Then, set onClickListener to the responding view. Lastly, to refresh your displaying list, call notifyDataSetChanged() or similar methods.
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
// declaration and setup here
final index = position;
// Define the logic to change the color if clicked item is/not in the list
if (yourClickedItemList.contain(position)) {
// Change what you want
}
else {
// Change what you want if the item is not in the list
}
// Then set the click listener
viewHolder.yourItemLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!yourClickedItemList.contain(index)) {
yourClickedItemList.add(index);
}
else {
// the list already contain that item
// do whatever you want here, like toggle off selection and remove from the list
}
// call to refresh your view
notifyDataSetChanged(); // or use notifyItemChanged() etc
}
}
}
So i have a recycler view loaded with items containing text and image and a checkbox. All the data is loaded just fine initially including the images using picasso. The checkbox is initially hidden, once i tap a button, which is not part of the recycler view. The checkboxes should appear in all the items of recycler view. Everything works fine except for the fact that the images disappear once i do that.
The way i am doing it is that i set the adapter to my recyclerview to null and then initialize a new recycler view adapter which has checkboxes visible and set it to my recycler view.
The same thing happens if i try to search for a particular list item using a search bar on top. Any idea why? Here is the code about how i am setting the adapter to my recycler view.
// set the adapter to null on cards list view.
cards_list_view.setAdapter(null);
// Initialize the adapter again.
deckCardRecycleAdapter = new DeckCardRecycleAdapter(getActivity(), cards_list, show_checkbox);
// Set the adapter again to list view.
cards_list_view.setAdapter(deckCardRecycleAdapter);
And here is my onBindViewHolder function in adapter.
#Override
public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/futura-medium.otf");
viewHolder.user_name.setTypeface(typeface);
viewHolder.user_name.setText(cards.get(position).getName().toString());
viewHolder.position.setTypeface(typeface);
viewHolder.position.setText(cards.get(position).getPosition().toString());
viewHolder.dot.setTypeface(typeface);
viewHolder.event_saved.setTypeface(typeface);
if(cards.get(position).getEvent_name().toString().equals("None")) {
viewHolder.event_saved.setVisibility(View.GONE);
viewHolder.dot.setVisibility(View.GONE);
}
else
viewHolder.event_saved.setText(cards.get(position).getEvent_name().toString());
viewHolder.date_saved.setTypeface(typeface);
String timestamp = cards.get(position).getTimestamp().toString();
viewHolder.date_saved.setText(toDate(timestamp));
if(cards.get(position).image_url.toString().equals("None"))
viewHolder.user_image.setImageResource(R.drawable.anonymous);
else {
String url_image = cards.get(position).image_url.toString();
Picasso.with(this.context).cancelRequest(viewHolder.user_image);
Picasso.with(context).load(url_image).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
viewHolder.user_image.setImageBitmap(bitmap);
cards.get(position).setImage_url(getStringImage(bitmap));
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
}
Please help. Thanks in advance.
I don't think it's a good idea to reload data each time, it's make a lot of performance instead you can create interface and let the item listening to it, and just with one line of code you can change the visibility
Check this answer
interface Listener {
public void onVisibilityChanged(bool visible);
}
create an interface (set bool parameter for visible/invisible)
Create separate class for manage listener's (like this)
add listener for each item (make checkbox visible or invisible)
remove listener when item removed (avoid NullpointException)
clear listener's if recycler reset (avoid NullpointException)
call the method that have foreach and all the listeners will be triged
I have got a RecyclerView item looking like this
I want to achieve that when I click on item the ImageView will get overlay over it and TextView will become bold. I know how to use adapter and where to handle item clicks. I also know how to make overlay or bold text. I only want to know how to make this item selectable to get the behavior I described above. Because I found only tutorials to change background of item when clicked.
Based on this
I only want to know how to make this item selectable to get the behavior I described above.
So basically you need a way to tell the ViewHolder that the current item is selected, such that in onBindViewHolder() the items are rendered as per need.
I can think of this: Make a model of the item youre adding to the RecyclerView. Add a key as boolean isSelected = false in it.
And inside your onBindViewHolder where youre implementing the onClick()interface. do this:
... new OnClickListener({
... onClick(){
// take the item and set the isSelected flag
list.get(position).setIsSelected(true):
notifyDataSetChanged();
// alternatively you can also toggle this flag.
}
});
and while loading inside onBindViewHolder to this:
if (list.get(position).isSelected()) {
// highlight aka set overlay and bold text to view
} else {
// as per recyclerview doc, reset the views.
}
All you need is having a variable to hold the selected index. Then decorating the selected item in onBindViewHolder() method.
int selectedIndex = 0;
...
public void onBindViewHolder(ViewHolder viewHolder, int position) {
if (selectedIndex == position) {
// Do things you want
}
}
I have a horizontal recyclerview having radio button as recyclerview item. I have to select all other radio button as false without currently selected radio button. So I have done -
View.OnClickListener rbClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
RadioButton checked_rb = (RadioButton) v;
if (lastCheckedRB != null && lastCheckedRB != checked_rb) {
lastCheckedRB.setChecked(false);
}
lastCheckedRB = checked_rb;
}
};
mainHolder.radioBtnTrip.setOnClickListener(rbClick);
Its working fine when i have 4 to 5 items. But when it has more than 5 items then always multiple radio button is selected as true because of view recycle. Given photo indicate that first item is selected but also 10th radio button is selected when I scroll.
How to resolve the row item position issue. I must have to select only one radio button at a time and select all other radio button of recyclerview as false.
Override the method getItemViewType to format the viewholder in many different way based on the value ( or whatever ) of the view
#Override
public int getItemViewType(int position) {
// example
return 0;
}
then, in your onBindViewHolder method
#Override
public void onBindViewHolder(Adapter.ViewHolder viewHolder, int position) {
if( this.getItemViewType(position)==1){
// layout #1
}else{
// layout #2
}
}
Understand the way recyclerview or listview works
You have to store the checked status somewhere to update when the bindview is called , where you can set the checked status to true.
Listview or RecyclerView will reuse view from any index on scrolling.
Same view that you have selected before cannot be expected on the same index when your scrolling back.
A simple way to do this is to create a property in the respective model and then inside onBindViewHolder() set the radio buttons checked property according to the model