I have made horizontal RecyclerView to show images where you select different actions by touching image. I have also highlighted current active selection by using background drawable and set that on onBindViewHolder.
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.itemView.setSelected(selectedPos == position);
holder.imageView.setImageResource(horizontalList.get(position).imageId);
then i have button which is not part RecyclerView so you can also roll selection in recyclerview to next one by pressing it.
It's working fine except highlighting doesn't change when pressing button.
I can test that when selecting currently selected item, i get my instructions activity opened otherwise different activity will be opened.
So how i can get that current selected item highlight when pressing a button??
update 1.
I have in my activity under myButtonOnClick
int mItemCount = horizontalAdapter.getItemCount() - 1;
horizontalAdapter.notifyItemChanged(selectedItem);
if (selectedItem == mItemCount) {
selectedItem = 0;
} else {
selectedItem += 1;
}
horizontalAdapter.notifyItemChanged(selectedItem);
which doesn't do much.
update 2.
Found the problem which was at my onBindViewHolder as i declared there different variable which messed things up.
so horizontalAdapter.notifyItemChanged(selectedItem); worked just fine and my
onBindViewHolder now i have holder.itemView.setSelected(selectedItem == position);
so manipulate same variable from both button and recyclerview to get things right.
You can add an OnScrollListener to your RecyclerView to observe any change in scroll state and position.
ref to this
If it doesn't help, you may paste your code inside the button.OnClickListener for further discussion.
Related
I'm having a problem when clicking on a CardView. I have a RecyclerView with CardViews where I want to do a single select. First click does it correctly, but when I click on another one the text color of the previous CardView changes to white.
Here is the code for my Adapter:
holder.setiRecyclerItemSelectedListener(new IRecyclerItemSelectedListener() {
#Override
public void onItemSelectedListener(View view, int pos) {
// Loop all cards in card list
for (CardView cardView: cardViewList) {
if (cardView.getTag() == null) // Only available card time slots
{
cardView.setCardBackgroundColor(context.getColor(R.color.colorWhite));
holder.txt_time_slot.setTextColor(context.getColor(android.R.color.tab_indicator_text));
holder.txt_time_slot_description.setTextColor(context.getColor(android.R.color.tab_indicator_text));
}
}
// Color of selected card time slot
holder.card_time_slot.setCardBackgroundColor(context.getColor(R.color.colorPrimaryLight));
holder.txt_time_slot.setTextColor(context.getColor(R.color.colorWhite));
holder.txt_time_slot_description.setTextColor(context.getColor(R.color.colorWhite));
// Send broadcast to enable button NEXT
Intent intent = new Intent(Common.KEY_ENABLE_BUTTON_NEXT);
intent.putExtra(Common.KEY_TIME_SLOT, position); // Put index of time slot we have selected
intent.putExtra(Common.KEY_STEP, 3);
localBroadcastManager.sendBroadcast(intent);
}
});
Pictures:
First one does it correctly
Second one doesn't
Define a selected index in adapter:
int selectedIndex = -1;
You can access child of recyclerView with this method:
findViewHolderForAdapterPosition(position);
change onClicklistener:
if (selectedIndex != -1)
{
YourHolder holderOld = (YourHolder) recycleView.findViewHolderForAdapterPosition(selectedIndex);
holderOld.cardView.setCardBackgroundColor(context.getColor(R.color.colorWhite));
holderOld.txt_time_slot.setTextColor(context.getColor(android.R.color.tab_indicator_text));
holderOld.txt_time_slot_description.setTextColor(context.getColor(android.R.color.tab_indicator_text));
}
selectedIndex = pos;
holder.card_time_slot.setCardBackgroundColor(context.getColor(R.color.colorPrimaryLight));
holder.txt_time_slot.setTextColor(context.getColor(R.color.colorWhite));
holder.txt_time_slot_description.setTextColor(context.getColor(R.color.colorWhite));
I guess you should invalidate your views in RecyclerView. So according to your question I think that you should call notifyDataSetChanged() function or you should invalidate specific item in RV by calling notifyItemChanged(position). Hope it'll help
I thought you implied colour of selected card time functions out of the } the machine using it and end the previous function without changing it that might be help
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 am trying to get a ViewPager and a RecyclerView to work in sync in displaying an image. The ViewPager contains an ImageView which shows a full sized image and the recycler view shows thumbnails of previous and upcoming images.
If the user swipes on the ViewPager then the RecyclerView moves left/right in sync. If the user scrolls and then clicks a photo, the ViewPager sets that position.
This all works, just giving background to my app.
The part I am stuck on is showing a border around the thumbnail that is currently selected in the RecyclerView from onPageSelected. The element which is considered selected is the one that is currently show on the ViewPager
A lot of the other questions deal with this problem using the onClickListener. My onClickListener just calls
viewPager.setCurrentItem(index)
So any time an item is selected, onPageSelected is called, either naturally from the ViewPager or from the click event. So this is where I feel I need to set the border.
So far I'm using a bit of a hack since the number of images is only 20.
for (int i = 0, ii = recyclerViewAdapter.getItemCount(); i < ii; i++) {
//RecyclerView.ViewHolder holder = recyclerView.findViewHolderForItemId(recyclerViewAdapter.getItemId(i));
RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(position);
if (holder instanceof RecyclerViewAdapter.RecyclerViewHolder) {
if (i == position) {
...
((RecyclerViewAdapter.RecyclerViewHolder) holder).getViewHolderContainer().setBackground(border);
} else {
((RecyclerViewAdapter.RecyclerViewHolder) holder).getViewHolderContainer().setBackground(null);
}
}
}
This doesn't work. If get's the right position since I'm provided that by the ViewPager but neither method for retrieving the ViewHolder at 'position' seems to work.
So, after all that, my question is if anyone can recommend me a clean way (or really even a hack at this point) that will let me update the current position of an element based on the position from onPageSelected of the ViewPager.
Thank you kindly.
So I ended up getting this working using two interfaces. No ugly looping hacks required.
ViewPager.OnPageChangeListener and OnChildAttachStateListener.
Basically my issue was that if I scrolled away from the currently selected item in the RecyclerView then I couldn't unselect that item later because the ViewHolder was recycled or null. Basically I couldn't access the previous view to unselect it so multiple items would end up selected when you scroll through it.
So with the ViewPager it was easy.
#Override
public void onPageSelected(int position)
int previousItemPos = currentItemPos; //currentItemPos is a class attr
currentItemPos = position;
int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation()
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_270) { //portrait
portraitScroll(position) //scrolls the recyclerView to currently selected item based on viewWidth
} else if .. landscape do the same
changeItem(position, previousItemPos);
}
#Override
public void onChildViewAttachedToWindow(View view) {
int childPosition = recyclerView.getChildAdapterPosition(view);
if (childPosition == currentItemPos) {
highlightItem(view); //applies an effect
}
}
#Override
public void onChildViewDetachedToWindow(View view) {
unHighlightItem(view);
}
private void changeItem(int newItem, int oldItem) {
ViewHolder holder = recyclerView.findViewHolderForItemId(recyclerView.getItemId(newItem));
if (holder instance of RecyclerViewHolder) {
highlightItem((RecyclerViewHolder) holder).getViewHolderContainer());
}
ViewHolder oldHolder = recyclerView.findViewHolderForItemId(recyclerView.getItemId(oldItem));
if (oldHolder instance of RecyclerViewHolder) {
unHighlightItem((RecyclerViewHolder) holder).getViewHolderContainer());
}
So basically each time we scroll so that the currently selected item in the ViewPager goes out of sight, we unselect it when it is detached. If we scroll back to it and the position hasn't changed, we reselect it.
If the ViewPager changes item, first we scroll to that item based on the width of the each RecyclerViews view, then we select it in onPageSelected.
I have a recyclerView in which i have a list of items displayed in a LinearLayout.There is a "increase" button in every list which will increment a quantity by "1".But when I click the button on the first list item to increment the number..the incremented value is displayed in the last list item of the recyclerView not in the desired position where i clicked.Can anyone help me find the solution?
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
myholder = holder;
holder.item_name_text.setText(data.get(position).getName());
holder.item_price_text.setText(data.get(position).getPrice().toString());
holder.item_quantity_text.setText("500");
//Adding item to the cart
holder.add_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(totalItem>=0 && totalItem<10){
totalItem++;
myholder.item_totalquantity_text.setText(String.valueOf(totalItem));
}else{
Toast.makeText(myholder.itemView.getContext(),"Cannot add more item",Toast.LENGTH_SHORT).show();
}
}
});
So I always think of recyclerviews as the frontend that displays my data. If you would like to make changes to the actual data itself and make sure it gets reflected in the recyclerview, you will need to ensure the changes are made inside the arraylist of data objects.
You will need to add a field inside the data object and call it counter. Then you must increment the counter once the user clicks on the onClickListener.
myholder.item_totalquantity_text.setText(data.get(position).setCounter(data.get(position).getCounter())+1);
Do not set OnClickListener() in onBindViewHolder(). Instead do it in your ViewHolder class itself. And main ly as RecyclerView re-uses the holder objects to represent the new set of data that is becoming visible. So the listener on which yo click might be belonging to some other view holder so it appears there instead.
Have a quick read of this and this. These are not very relevant to you but it has info to understnad recycling concept so you can fix your stuff easily.
I have a horizontal Recyclerview which displays bitmaps.
The Way it is implemented is I have a Imageview and a recyclerview underneath it. The currently selected item is displayed on the image view. The selected image view is given a blue background to indicate it is selected. I can choose images from the gallery and each time a new image is selected, I want to scroll to the last position and make the item selected.
The list of images is maintained in a array list and each time a new image is added, I add the image to the list and notifyDataChanged().
Currently when I am binding a view, I toggle the visibility of the blue background in
public void onBindViewHolder(final MyRecyclerViewHolder holder, int position) {
}
But the problem is, if the child is off screen, the bind view is not called and I dont scroll to the new position.
I read through the documentation of recycler view and could not figure out how to scroll to that particular child view. I do not there is a SmoothScrollTo method but my question is where do I trigger this ?
There is one solution:
In your RecyclerView adapter, add a variable selectedItem and a methods setSelectedItem():
private static int selectedItem = -1;
... ...
public void setSelectedItem(int position)
{
selectedItem = position;
}
In your onBindViewHolder(...), add:
#Override
public void onBindViewHolder(ViewHolder holder, final int position)
{
... ...
if(selectedItem == position)
holder.itemView.setSelected(true);
}
Now you can scroll to specific item and set it selected programmatically by:
myRecyclerViewAdapter.setSelectedItem(position_scrollTo);
myRecyclerView.scrollToPosition(position_scrollTo);
For example, you want to scroll to last position and make it selected, just:
int last_pos = myRecyclerViewAdapter.getItemCount() - 1;
myRecyclerViewAdapter.setSelectedItem(last_pos);
myRecyclerView.scrollToPosition(last_pos);
[UPDATE]
To add item and make it selected, you should have a addItem(...) method in adapter, which will add item to item list. After adding item, refresh list and scroll to new added/latest item:
myRecyclerViewAdapter.addItem(...);
myRecyclerViewAdapter.notifyDataSetChanged();
myRecyclerViewAdapter.setSelectedItem(myRecyclerViewAdapter.getItemCount() - 1);
myRecyclerView.scrollToPosition(myRecyclerViewAdapter.getItemCount() - 1);
Hope this help!
Your view will not be created until you scroll to the item.
You must call
recyclerView.scrollToPosition(position)
Where position is
recyclerView.getAdapter().size()
So the item became visible.
Use RecyclerView LayoutManager to scroll item at position
recyclerView.getLayoutManager().scrollToPosition(position)
I forgot to address the timing part ideally this should be called when the adapter has been identified of the dataset change.
You could use
recyclerView.smoothScrollToPosition(View.FOCUS_DOWN);