Inconsistent Background Color Changes in RecyclerView? - java

I am trying to Change the Background of certain CardViews when the user click and Opens the particular items.
This is achieved, but as I scroll to bottom or top, certain other cards also change their colors. Why is that ? Can u guys please provide a Fix.
Here is my Adapter Code :
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.resources_layout, parent, false);
return new ResourcesAdapter.ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, int position) {
final ResourcesModel resourcesModel = resourcesModelList.get(position);
holder.book_title.setText(resourcesModel.getBook_title());
holder.book_description.setText(resourcesModel.getBook_description());
holder.book_price.setText(resourcesModel.getBook_price());
Glide.with(context).load(resourcesModel.getBook_image()).placeholder(R.drawable.placeholder).into(holder.book_image);
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, ResourcesDetails.class);
intent.putExtra("Title", resourcesModel.getBook_title());
intent.putExtra("Description", resourcesModel.getBook_description());
intent.putExtra("Price", String.valueOf(resourcesModel.getBook_price()));
intent.putExtra("BookImage", resourcesModel.getBook_image());
intent.putExtra("PDFS", resourcesModel.getPdf());
context.startActivity(intent);
}
});
String k = holder.book_title.getText().toString();
SharedPreferences myPreferences;
SharedPreferences.Editor myEditor;
myPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String name = myPreferences.getString(k, "notWatched");
Log.e("Name Value ADAPTER :", String.valueOf(name));
if (myPreferences.contains(k)) {
holder.cardView.setBackgroundColor(context.getResources().getColor(R.color.color_bought));
}
#Override
public int getItemCount() {
return resourcesModelList.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
ImageView book_image;
TextView book_title, book_description, book_price, pdfLinks;
Button buy_btn;
MaterialCardView cardView;
ImageView tick;
public ViewHolder(#NonNull View itemView) {
super(itemView);
book_image = itemView.findViewById(R.id.book_img);
book_title = itemView.findViewById(R.id.book_title);
book_description = itemView.findViewById(R.id.book_description);
book_price = itemView.findViewById(R.id.book_price);
cardView = itemView.findViewById(R.id.cardView);
}

if (myPreferences.contains(k)) {
holder.cardView.setBackgroundColor(context.getResources().getColor(R.color.color_bought));
}
You're not setting the background color back to the default if it's not in myPreferences. Because of ViewHolder recycling, you need an } else { case to handle this.

Related

How to block particular Position in Adapter class ANDROID JAVA

I have an adapter class Where i Want to show a BLOCK USER dialog on particular position.
for example if i want to block position 1 of recyclerView .
So can any one help me porgrammatically?
Given below is the Code Of adapter Please check
I want to block user profile based on Recycler View position
if someone could help me in it please;
public class TableProfileAdapter extends RecyclerView.Adapter<TableProfileAdapter.MyViewHolder> {
Context context;
Activity getActivity;
List<TableProfile> profileUser;
OnRecItemClick onRecItemClick;
private boolean isScaleAnimationDone = false;
private boolean isTimerTextViewActionUpCalled = false;
public TableProfileAdapter(List<TableProfile> profileUser, Context context) {
this.profileUser = profileUser;
this.context = context;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.profile_item, parent, false);
return new MyViewHolder(view, onRecItemClick);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position) {
TableProfile data = profileUser.get(position);
holder.tvUserName.setText(data.getProfileName());
Bitmap image = BitmapManager.byteToBitmap(data.getProfileImage());
holder.profilePic.setImageBitmap(image);
if (context instanceof AccessProfileManagementActivity) {
context.startActivity(new Intent(context,HomeActivity.class));
} else if (context instanceof ProfileManagement) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context, ProfileDetailsActivity.class);
TableProfile model = profileUser.get(holder.getAdapterPosition());
intent.putExtra("DATA", model);
context.startActivity(intent);
notifyDataSetChanged();
((Activity) context).finish();
}
});
}
}
#Override
public int getItemCount() {
return profileUser.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
CircleImageView profilePic;
TextView tvUserName, birthday;
OnRecItemClick onRecItemClick;
RelativeLayout relativeLayout;
public MyViewHolder(#NonNull View itemView, OnRecItemClick onRecItemClick) {
super(itemView);
profilePic = itemView.findViewById(R.id.profileImage);
tvUserName = itemView.findViewById(R.id.userName);
relativeLayout = itemView.findViewById(R.id.relTop);
this.onRecItemClick = onRecItemClick;
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
onRecItemClick.onItemClick(getAdapterPosition());
}
}
public interface OnRecItemClick {
void onItemClick(int position);
}
}

On Clicking one button, it Triggers another button in recycle view

I'm currently working on a attandance management Android app. In my recyclerview there are list of student detail being populated dynamically from database. When i click the first button in the list, it also change the button colour of the 11th button of the list Like wise to 2nd button click changes the colour of 12th View button
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
Context context;`enter code here`
List<StudentDetails> MainImageUploadInfoList;
public RecyclerViewAdapter(Context context, List<StudentDetails> TempList) {
this.MainImageUploadInfoList = TempList;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_items, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
StudentDetails studentDetails = MainImageUploadInfoList.get(position);
holder.StudentNameTextView.setText(studentDetails.getName());
holder.StudentNumberTextView.setText(studentDetails.getPhoneNumber());
holder.st.setText(studentDetails.getRollno());
holder.cardView.setCardBackgroundColor(getcolor(position));
}
private int getcolor(int position) {
return Color.parseColor("#" + Integer.toHexString(ContextCompat.getColor(context, R.color.normal)));
}
#Override
public int getItemCount() {
return MainImageUploadInfoList.size();
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView StudentNameTextView;
public TextView StudentNumberTextView;
public TextView st;
DatabaseReference databaseReference;
String se,wh,su,d;
Button b;
CardView cardView;
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
StudentNameTextView = (TextView) itemView.findViewById(R.id.ShowStudentNameTextView);
StudentNumberTextView = (TextView) itemView.findViewById(R.id.ShowStudentNumberTextView);
st = (TextView) itemView.findViewById(R.id.studentrollno);
cardView=itemView.findViewById(R.id.cardview1);
se=Teacher.getInstance().getSe();
wh=Teacher.getInstance().getWh();
su=Teacher.getInstance().getSu();
d=Teacher.getInstance().getD();
b=itemView.findViewById(R.id.button3);
itemView.findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view ) {
int position=getAdapterPosition();
String message = String.valueOf(position) ;
databaseReference= FirebaseDatabase.getInstance().getReference("attandance").child(wh).child(se).child(su).child(d).child(message);
databaseReference.setValue("p");
itemView.findViewById(R.id.button3).setBackgroundColor(Color.GREEN);
itemView.findViewById(R.id.button4).setEnabled(false);
itemView.findViewById(R.id.button3).setEnabled(false);
Toast.makeText( context,"position is "+String.valueOf(position), Toast.LENGTH_SHORT).show();
}
});
itemView.findViewById(R.id.button4).setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(final View view ) {
int position=getAdapterPosition();
String message = String.valueOf(position) ;
databaseReference= FirebaseDatabase.getInstance().getReference("attandance").child(wh).child(se).child(su).child(d).child(message);
databaseReference.setValue("A");
itemView.findViewById(R.id.button4).setBackgroundColor(Color.RED);
itemView.findViewById(R.id.button3).setEnabled(false);
itemView.findViewById(R.id.button4).setEnabled(false);
}
});
}
#Override
public void onClick(View view) {
// int position=this.getAdapterPosition();
// Intent intent=new Intent(context,mark.class);
// String message = String.valueOf(position);
// intent.putExtra("attan",message);
// context.startActivity(intent);
// Intent intent = new Intent(context,mark.class);
//String message = String.valueOf(position) ;
//intent.putExtra("attan",message);
//context.startActivity(intent);
// Toast.makeText( context,"position is "+String.valueOf(position), Toast.LENGTH_SHORT).show();
}
}
}
}

Do not treat position as fixed; only use immediately

I have this error in my code:
Do not treat position as fixed; only use immediately and call holder.getAdapterPosition() to look it up later.
I even used holder.getAdapterPosition() in the position place, but it still keeps crashing the app when I click the items.
MusicAdapter(Context mcontext, ArrayList<MusicFile> mfiles) {
this.mfiles = mfiles;
this.mcontext = mcontext;
}
#Override // androidx.recyclerview.widget.RecyclerView.Adapter
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(this.mcontext).inflate(R.layout.music_items, parent, false));
}
public void onBindViewHolder( final MyViewHolder holder, int position) {
holder.file_name.setText(this.mfiles.get(position).getTitle());
byte[] image = getAlbumArt(this.mfiles.get(position).getPath());
if (image != null) {
Glide.with(this.mcontext).asBitmap().load(image).into(holder.album_art);
} else {
Glide.with(this.mcontext).load((int) R.drawable.ic_launcher_background).into(holder.album_art);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent intent = new Intent(MusicAdapter.this.mcontext, PlayerActivity.class);
intent.putExtra("position", holder.getAdapterPosition());
MusicAdapter.this.mcontext.startActivity(intent);
}
});
}
#Override // androidx.recyclerview.widget.RecyclerView.Adapter
public int getItemCount() {
return this.mfiles.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
ImageView album_art;
TextView file_name;
LinearLayout linearLayout;
public MyViewHolder(View itemView) {
super(itemView);
this.file_name = (TextView) itemView.findViewById(R.id.music_file_name);
this.album_art = (ImageView) itemView.findViewById(R.id.music_img);
linearLayout = itemView.findViewById(R.id.linear_layout);
}
}
private byte[] getAlbumArt(String uri) {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(uri);
byte[] art = retriever.getEmbeddedPicture();
retriever.release();
return art;
}
}
Imagine that we have a RecyclerView that will display 10 items so it will create 10 items and call onBindView for those 10 items and pass the positions from 0 to 9, so if you fixed the position by using it to handle user clicks and later you added an item at position 0 and notified the data set that you inserted a new item by notifyItemInserted() the RecyclerView will create a new item with position 0 and pass it to the layout but the pre created ones still have the old positions and if you logged those positions you will have 00123…9 which is not true it should be 0123…10. Here come the power of holder.getAdapterPosition().
#Override
public void onBindViewHolder(#NonNull GalleryViewAdapter holder,final int position) {
Glide.with(context).load(images.get(position)).into(holder.imageView);
holder.imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, FullImageview.class);
intent.putExtra("image", images.get(holder.getAdapterPosition()));
context.startActivity(intent);
}
});
}
now its fine to use holder.getAdapterPosition for user click event
notice that i used getAdapterPosition to bind data and used getLayoutPosition to tell the user the position of the pressed item.

viewHolder.getAdapterPosition() in adapter return -1 position and it caused IndexOutOfBoundException

i try to implement best practice to handle onclick in adapter, but i got problem IndexOutOfBoundException when getAdapterPostition inside onCreateViewHolder, whats wrong with my code?
i already try to check but not solve yet.
public class VideoAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private DataFrontVideo datas;
private Context context;
public VideoAdapter(DataFrontVideo datas, Context context) {
this.datas = datas;
this.context = context;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_video,null);
final ViewHolder viewHolder = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DataVideo video = datas.getContent().get(viewHolder.getAdapterPosition()); // ERROR HERE
Intent intent = new Intent(context,DetailActivity.class);
intent.putExtra("datas",video);
context.startActivity(intent);
}
});
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int position) {
DataVideo dataVideo = datas.getContent().get(position);
ViewHolder vh = (ViewHolder)viewHolder;
vh.tvTitle.setText(dataVideo.getJudul());
vh.tvArtis.setText(dataVideo.getAlias());
vh.tvPrice.setText((dataVideo.getPrice().equals("0")?"Gratis":dataVideo.getPrice()));
Glide.with(vh.img.getContext()).load(dataVideo.getThumb_pic()).into(vh.img);
}
#Override
public int getItemCount() {
return (datas == null)? 0 : datas.getContent().size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private ImageView img;
private TextView tvTitle,tvArtis,tvPrice;
public ViewHolder(#NonNull View itemView) {
super(itemView);
img = itemView.findViewById(R.id.imgVideo);
tvArtis = itemView.findViewById(R.id.tvartis);
tvTitle = itemView.findViewById(R.id.tvTitle);
tvPrice = itemView.findViewById(R.id.tvPrice);
}
}
}
it should not return -1
Inside your ViewHolder you need to apply the setOnClickListener and get the item position on click by using the getAdapterPosition() like below
public class ViewHolder extends RecyclerView.ViewHolder{
private ImageView img;
private TextView tvTitle,tvArtis,tvPrice;
public ViewHolder(#NonNull View itemView) {
super(itemView);
img = itemView.findViewById(R.id.imgVideo);
tvArtis = itemView.findViewById(R.id.tvartis);
tvTitle = itemView.findViewById(R.id.tvTitle);
tvPrice = itemView.findViewById(R.id.tvPrice);
YOUR_VIEW.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(mContext,"Position==>> "+getAdapterPosition(),Toast.LENGTH_LONG).show();
DataVideo video = datas.getContent().get(viewHolder.getAdapterPosition()); // ERROR HERE
Intent intent = new Intent(context,DetailActivity.class);
intent.putExtra("datas",video);
context.startActivity(intent);
}
});
}
}
Actually, the problem just because you are registering click listener in your onCreateViewHolder which is wrong you need to register on Click listener in your onBindViewHolder like bellow
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int position) {
DataVideo dataVideo = datas.getContent().get(position);
ViewHolder vh = (ViewHolder)viewHolder;
vh.tvTitle.setText(dataVideo.getJudul());
vh.tvArtis.setText(dataVideo.getAlias());
vh.tvPrice.setText((dataVideo.getPrice().equals("0")?"Gratis":dataVideo.getPrice()));
Glide.with(vh.img.getContext()).load(dataVideo.getThumb_pic()).into(vh.img);
vh.parentView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context,DetailActivity.class);
intent.putExtra("datas",dataVideo);
context.startActivity(intent);
}
});
}
Move your click in onBindViewHolder .Here it will work for title click ,if you want all click make viewholder complete layout and implement click listener
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder viewHolder, int position) {
DataVideo dataVideo = datas.getContent().get(position);
ViewHolder vh = (ViewHolder)viewHolder;
vh.tvTitle.setText(dataVideo.getJudul());
vh.tvArtis.setText(dataVideo.getAlias());
vh.tvPrice.setText((dataVideo.getPrice().equals("0")?"Gratis":dataVideo.getPrice()));
Glide.with(vh.img.getContext()).load(dataVideo.getThumb_pic()).into(vh.img);
vh.tvTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context,DetailActivity.class);
intent.putExtra("datas",dataVideo );
context.startActivity(intent);
}
});
}

Listener interface isn't working with onClick for cardviews in a recycler view

I have several cardviews on my layout. When one gets clicked it should call my Listener's onClick method which will start EquationsActivity and pass it the position of the card. That is not working. My recyclerFragment is in a tablayout. I've looked and looked and I can't seem to figure out the problem! All suggestions are appreciated!!
My recyclerAdapter:
public class recylcerAdapter extends RecyclerView.Adapter<recylcerAdapter.ViewHolder> {
private Listenerr listener;
private int[] imageIds;
private String[] nameArray;
public interface Listenerr{
void onClick(int position);
}
public static class ViewHolder extends RecyclerView.ViewHolder{
private CardView cardView;
public ViewHolder(CardView v){
super(v);
cardView = v;
}
}
public recylcerAdapter(Context context, String title, Cursor cursor, int[]imageIds, String[]nameArray){
this.imageIds = imageIds;
this.nameArray = nameArray;
}
public void setListener(Listenerr listener){
this.listener = listener;
}
#Override
public recylcerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
//create a new view
CardView cardView = (CardView) LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_main, parent, false);
return new ViewHolder(cardView);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position){
//set the values inside the given view
CardView cardView = holder.cardView;
ImageView imageView = (ImageView) cardView.findViewById(R.id.list_icon);
Drawable drawable = cardView.getResources().getDrawable(imageIds[position]);
imageView.setImageDrawable(drawable);
imageView.setContentDescription(nameArray[position]);
TextView textView = (TextView) cardView.findViewById(R.id.card_text);
textView.setText(nameArray[position]);
cardView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
if(listener != null){
Log.v("hitsOnClick", "It has been hit");
listener.onClick(position);
}
}
});
}
#Override
public int getItemCount(){
//return number of items in the data set
return nameArray.length;
}
}
My recycler fragment code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
new listPop().execute();
RecyclerView recyclerView = (RecyclerView) inflater.inflate(R.layout.recylcler_layout, container, false);
recylcerAdapter RecylcerAdapter =
new recylcerAdapter(getActivity(), "Geometry", cursor, imageArray, names.toArray(new String[names.size()]));
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(RecylcerAdapter);
RecylcerAdapter.setListener(new recylcerAdapter.Listenerr() {
#Override
public void onClick(int position) {
Intent intent = new Intent(getActivity(), EquationsActivity.class);
intent.putExtra(EquationsActivity.POSITION, position);
getActivity().startActivity(intent);
}
});
return recyclerView;
}
EDIT:
with more looking I have found that when I tap on a card, the onClick in the onbindviewholder is not being hit.
Let's setup the click listener when you create new view holder:
public static class ViewHolder extends RecyclerView.ViewHolder{
CardView cardView;
ImageView imageView;
TextView textView;
public ViewHolder(CardView v){
super(v);
cardView = v;
imageView = (ImageView) cardView.findViewById(R.id.list_icon);
textView = (TextView) cardView.findViewById(R.id.card_text);
}
}
And modify a little bit when binding and creating:
#Override
public recylcerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
//create a new view
final CardView cardView = (CardView) LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_main, parent, false);
cardView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
if(listener != null){
Log.v("hitsOnClick", "It has been hit");
listener.onClick((int)cardView.getTag());
}
}
});
return new ViewHolder(cardView);
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position){
//set the values inside the given view
Drawable drawable = holder.cardView.getResources().getDrawable(imageIds[position]);
holder.imageView.setImageDrawable(drawable);
holder.imageView.setContentDescription(nameArray[position]);
holder.textView.setText(nameArray[position]);
holder.cardView.setTag(position);
}

Categories