Hilighted/Selected items colour changes when not in view in RecyclerView - android

I have a RecyclerView with a large list of items. This RecyclerView has OnScrollListener for endless scrolling.
When an item is selected I highlight it with a specific colour and
when unselected the colour changes to normal/white.
The issue that I am facing is after selecting a few visible items in my view when I scroll up or down to select a few more items the colour of already selected items changes to white.
I tried adding a boolean variable (isSelected) in the model class and highlight the selected item but still I am facing the same issue as earlier. Currently the recyclerView allows to select just one item from the view and after some research I figured some of the concepts were taken from this article to implement single item selection. I wonder how do I modify/tweak this code to be able to select multiple items.
I am not presenting the code as it is quite huge and is confidential but if there is any general fix for this scenario then what would it be?
Background: the application is a chat app and I am showing the sent and received texts. The user should be able to select a few specific texts and should be able to share it with someone else.
Edit: I am putting the code in my onBindViewHolder:
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final PostDataColumns mPostDataColumns = data.get(position);
holder.textCardView.setBackgroundColor(mPostDataColumns.isSelected() ? getResources().getColor(R.color.long_press):
getResources().getColor(android.R.color.white));
holder.textCardView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
mPostDataColumns.setSelected(!mPostDataColumns.isSelected());
if(mPostDataColumns.isSelected()) {
holder.textCardView.setBackgroundResource(R.color.long_press);
multipleSelectedPositions.add(holder.getLayoutPosition());
} else if(!mPostDataColumns.isSelected()) {
holder.textCardView.setBackgroundResource(android.R.color.white);
multipleSelectedPositions.remove(holder.getAdapterPosition());
}
//Adapter.this.onLongClick(holder, position);
return true;
}
});
holder.textCardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.textCardView.setBackgroundResource(android.R.color.white);
/* clearLongSelection(holder, position, alignParentRight,
data.get(position).getReceiverUserId().length() > 5); */
}
});
}
The code which I have commented in onCLick and onLongClick were used when the requirement was to select a single item.
these are the methods which were called in onClick and onLOngClick:
public boolean clearLongSelection(ViewHolder holder, int position) {
if (selectedPosition >= 0) {
if (selectedPosition == position) {
holder.parentLayout.setBackgroundResource(android.R.color.transparent);
if (alignParentRight) {
holder.mediaCardView.setBackgroundResource(android.R.color.white);
holder.assessmentCardView.setBackgroundResource(android.R.color.white);
holder.surveyCardView.setBackgroundResource(android.R.color.white);
holder.documentCardView.setBackgroundResource(android.R.color.white);
holder.textCardView.setBackgroundResource(android.R.color.white);
} else {
holder.mediaCardView.setBackgroundResource(R.color.long_press);
holder.assessmentCardView.setBackgroundResource(R.color.long_press);
holder.surveyCardView.setBackgroundResource(R.color.long_press);
holder.documentCardView.setBackgroundResource(R.color.long_press);
holder.textCardView.setBackgroundResource(R.color.long_press);
}
selectedPosition = -1;
invalidateOptionsMenu();
getSupportActionBar().setTitle(intentData.getName());
}
return true;
}
return false;
}
public void onLongClick(ViewHolder holder, int position) {
if (selectedPosition < 0) {
holder.parentLayout.setBackgroundResource(R.color.long_press);
holder.mediaCardView.setBackgroundResource(R.color.long_press);
holder.assessmentCardView.setBackgroundResource(R.color.long_press);
holder.surveyCardView.setBackgroundResource(R.color.long_press);
holder.documentCardView.setBackgroundResource(R.color.long_press);
holder.textCardView.setBackgroundResource(R.color.long_press);
selectedPosition = position;
invalidateOptionsMenu();
getSupportActionBar().setTitle("1 Selected");
} else {
}
}
The variable selectedPosition in onClick and clearLongSelection is initialised in the class as instance variable- selectedPosition = -1.

Use SparseBooleanArray to keep track of selected items in recycler view adapter
Initialize the SparseBooleanArray as private memeber variable
private SparseBooleanArray mClickedItems=new SparseBooleanArray();
Then inside your click function while clicking any item,store the clicked item position as true.
mClickedItems.put(getAdapterPosition(),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
}else {
//show unselected color
}

Related

Iterate All Items In RecyclerView

I have a RecyclerView of CardViews. I am trying to have it where you click on one of the CardViews and it changes the background of that CardView. This part works. Where I am stuck is trying to change all of the other CardViews back to white so it doesn't look like multiple are selected.
I feel the best way to do this is a for loop but I can't seem to find what the for loop should be. I also tried resetting all the CardViews with notifyDataSetChanged() but that did not work either.
Here is my onItemClicked() function (that works correctly):
mAdapter = new TransferCard(list, getContext(), new TransferCard.OnItemClickListener() {
#Override
public void onItemClick(View v, int position) {
//What code goes here to change all Views in the RecyclerView to have a background of white
RelativeLayout temp = v.findViewById(R.id.cardForeground);
item = list.get(position);
temp.setBackgroundColor(getResources().getColor(R.color.selected));
}
});
Here is my onCreateViewHolder() where the setOnTouchListener() event is.
#Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.transfer_card, parent, false);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemClick(v, parent.indexOfChild(v));
}
});
return new MyViewHolder(itemView);
}
It seems I am just about there, but I need to know what to do with the for loop.
for (int x = recyclerView.getChildCount(), i = 0; i < x; ++i) {
ViewHolder holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i));
}
In general, you should write your adapter in such a way that onBindViewHolder() is the only place where you modify your views. For what you're trying to do, I think the easiest thing to do would be to keep track of the last position that was tapped, and then have onBindViewHolder() set the background to black or white based on whether its position equals the last tapped position.
#Override
public void onItemClick(View v, int position) {
lastTappedPosition = position;
mAdapter.notifyDataSetChanged();
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (position == lastTappedPosition) {
// set color selected
} else {
// set color unselected
}
...
}
You could improve upon this by only notifying the adapter that the old tapped position and the new tapped position have changed (so that you don't have to re-bind every view), but in the interest of simplicity I left it as-is.
You should have a field like isSelected in you model, make it all as false for all the list items.
Pass it to your adapter.
In you adapter check condition in onBindViewHolder:
if (list.get(i).isSelected) {
// change background to black
} else {
// change background to white
}
Whenever you click on an item change just inverse the field item, ie make it true if it was false or make it false if it was true.
list.get(i),isSelected = !list.get(i).isSelected;
for (int x = recyclerView.getChildCount(), i = 0; i < x; ++i) {
RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i));
TextView txtAbc0 = holder.itemView.findViewById(R.id.txt_abc0);
TextView txtAbc1 = holder.itemView.findViewById(R.id.txt_abc1);
txtAbc0.setText("abc0="+i);
txtAbc1.setText("abc1="+i);
}

How to get control to other item in recyclerview?

I have a horizontal recyclerView,when I clicked on each of the element,a LinearLayout inside it setVisibility(VISIBLE) ,this work fine.
So what I want now is,when I clicked in current item,LinearLayout setVisibilty(VISIBLE)(as usual) at the same time,if I clicked another item before,the LinearLayout inside it setVisibility(GONE).
What I tried so far
viewHolder.container.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(viewHolder.linearLayout.getVisibility() == View.VISIBLE){
//hide
viewHolder.linearLayout.setVisibility(View.GONE);
}else{
int nowClickedId = 0;
//hide LinearLayout of other position that clicked before
if(nowClickedId != position){
viewHolder.linearLayout.setVisibility(View.GONE);
}
//show for current clicked item
viewHolder.linearLayout.setVisibility(View.VISIBLE);
//get current item position store at the array
nowClickedId = viewHolder.getAdapterPosition();
}
}
});
So far I just have control at the item in current position,how can get the control of the item of clicked previously?
Create a variable to store the position of the item clicked and declare it globally.
private int nowclicked=-1;
Now inside your viewholder whenever position is clicked store it to the global variable and call notifyDataSetChanged() which notifies the adapter that data is changed.
private class Sample extends RecyclerView.ViewHolder{
public Sample(View itemView) {
super(itemView);
viewHolder.container.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
nowclicked = getAdapterPosition();
notifyDataSetChanged();
}
});
}
}
In the onBindViewHolder if the posistion is equal show linearLayout else hide it.
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(nowclicked==position){
viewHolder.linearLayout.setVisibility(View.VISIBLE);
}else {
viewHolder.linearLayout.setVisibility(View.GONE);
}
}
Try to write this code inside the onBindViewHolder() method and ensure to write
holder.viewHolder.container.setOnClickListener();
And according the position you can do whatever you want.

How can I RecyclerView Different View Selected or UnSelected

I currently use RecyclerView but i can't fix the issue;
If user selected a answer, answer in change textview color and background.
If user selected different answer first answer old textview color and background.
Codes;
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
_mContext = holder._mAnswersContainer.getContext();
_mPosition = position;
holder._mImageAnswer.setImageDrawable(Utils.stringToResource(_mContext,
_mAnswerList.get(_mPosition).mAnswerImage));
holder._mImageTextAnswer.setText(_mAnswerList.get(_mPosition).mAnswerText);
holder._mAnswersContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder._mImageTextAnswer.setTextColor(_mContext.getResources()
.getColor(R.color.white));
holder._mImageTextAnswer.setBackgroundColor(_mContext.getResources()
.getColor(R.color.red));
Log.d(TAG, "Values : " + QuestionsHelper.getInstance(_mContext)
.getValues(_mAnswerList.get(_mPosition).mAnswerText));
}
});
}
Inside your adapter, make a member variable to keep track of which position is selected:
private int mSelected = -1;
Inside your onBindViewHolder (although it might work inside onCreateViewHolder as well):
int color;
if(position == mSelected){
color = ContextCompat.getColor(context, R.color.selectedColor);
}else{
color = ContextCompat.getColor(context, R.color.regularColor);
}
// Set the color
viewHolder.yourView.setBackgroundColor(color);
Create some helper functions for your RecyclerView adapter to handle the selection:
public void selectPosition(int selected){
mSelected = selected;
notifyDataSetChanged();
}
public void resetSelected(){
mSelected = -1;
notifyDataSetChanged();
}
Wherever you want to set the selected item just call adapter.selectPosition(). And clear the selection with adapter.resetSelected()

How to make listview selected one item element?

I am working on the custom Listview using BaseAdapter. I am facing one small issue after tap on listview item that particular row gets highlighted but after that if i'll tap one another list item it's highlighted but still the older one it remains same it's not going to it's previous state.
I want to see one item should select at one time.
MainActivity.java
if (musicRealmResults.get(currentIndex).isSelected() == false) {
musicRealmResults.get(currentIndex).setIsSelected(true);
playSong(currentIndex, true);
adapter.notifyDataSetChanged();
} else {
musicRealmResults.get(currentIndex).setIsSelected(false);
adapter.notifyDataSetChanged();
}
MusicAdapter.java
if (musicRealmResults.get(position).isSelected()) {
Typeface tf = Typeface.createFromAsset(mContext.getAssets(), "fonts/fonts_bold.otf");
holder1.albumsTextView.setTypeface(tf);
holder1.equalizerView.setVisibility(View.VISIBLE);
holder1.albumsImageView.setVisibility(View.INVISIBLE);
holder1.equalizerView.animateBars();
} else {
Typeface tf = Typeface.createFromAsset(mContext.getAssets(), "fonts/fonts_regular.otf");
holder1.albumsTextView.setTypeface(tf);
holder1.equalizerView.setVisibility(View.GONE);
holder1.albumsImageView.setVisibility(View.VISIBLE);
holder1.equalizerView.stopBars();
}
Please kindly go through my post and suggest me how to do select and deselect in a listview row.
Loop through all your array elements and set check state to false, then set currentIndex to true.
MainActivity
for(int i =0 ; i < musicRealmResults.size() ; ++i){
musicRealmResults.get(i).setIsSelected(false);
}
musicRealmResults.get(currentIndex).setIsSelected(true);
playSong(currentIndex, true);
adapter.notifyDataSetChanged();
Seems that you weren't able to setSelected(false) your previous item.
Please check setChoiceMode() of ListView or you may just reset your previous item to setSelected(false).
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
musicRealmResults.get(currentSelected).setIsSelected(false); //Reset previous
currentSelected = position; //Save currentPosition to for reset later
.....todos
}
This is a good alternative too, if u dont want to loop through the rest of positions to deselect them.
int prevSelection =-1; //nothing selected
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (prevSelection==-1) //nothing selected
{
musicRealmResults.get(position).setIsSelected(true);
adapter.notifyDataSetChanged();
prevSelection = position;
}else if (prevSelection == position) //deselect previously selected
{
musicRealmResults.get(position).setIsSelected(false);
adapter.notifyDataSetChanged();
prevSelection = -1;
}else // Some other selection
{
musicRealmResults.get(prevSelection).setIsSelected(false);
musicRealmResults.get(position).setIsSelected(true);
adapter.notifyDataSetChanged();
prevSelection = position;
}
You can manage this in your model class. Just make a toggle Boolean isSelected with its getter and setter, When user tap on list item check whether its already selected or not, if not then mark it as selected and update the Boolean value in your model class.
mListLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(list.get(position).getisSelected()){
// list item is already selected.
mListLayout.setBackgroundColor(Color.WHITE); // normal color
list.get(position).setisSelected(false);
}
else{
// list item is not selected, make it selected
mListLayout.setBackgroundColor(Color.GRAY); // selected color
list.get(position).setisSelected(true);
}
notifyDataSetChanged();
}
});
Try Below Code:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
if (musicRealmResults.get(position).isSelected() == false)
{
musicRealmResults.get(position).setIsSelected(true);
playSong(position, true);
adapter.notifyDataSetChanged();
}
else
{
musicRealmResults.get(position).setIsSelected(false);
adapter.notifyDataSetChanged();
}
}
});

Android custom listview adapter to stay highlighted selected item

I have a problem with my listview. What I want to do is when I click an item in the listview, it should remain highlighted, and when I click another item, new item should be highlighted.
Here's what I've done so far:
public void setSelection(int position) {
if (selectedPos == position) {
selectedPos = NOT_SELECTED;
} else {
selectedPos = position;
}
notifyDataSetChanged();
}
Adapter GetView:
if (position == selectedPos) {
// your color for selected item
viewHolder.tvTitle.setTextColor(context.getResources().getColor(R.color.main_blue));
viewHolder.tvDetails.setTextColor(context.getResources().getColor(R.color.main_blue));
}
else {
// your color for non-selected item
viewHolder.tvTitle.setTextColor(context.getResources().getColor(R.color.dark_grey));
viewHolder.tvDetails.setTextColor(context.getResources().getColor(R.color.dark_grey));
}
Activity:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
episodesAdapter.setSelected(position);
}
});
This is working as expected, but the problem is with notifyDataSetChanged, it's delaying the time to highlight item that is being selected next. What should I do to automatically get it highlighted? Any help would be truly appreciated. Thanks!
Update:
I tested and it took 8-10secs before a new item is highlighted. There is a slight delay in highlighting an item.

Categories

Resources