How to avoid RadioGroup checked twice in RecyclerView - java

I've noticed RecyclerView "recycle" the views in the adapter but i want stop RecyclerView adapter duplicate the checked action in another item of the RecyclerView.
I have 10 items drawed into a RecyclerView, each one of them have a RadioGroup with 2 RadioButton within, but when i fired the check in the first item, for example, the number ten item have a checked too.
I was reading this question but i could'nt got it work.
Using Radio button with recyclerview in android
How to avoid this?
My adapter:
...
public class PreguntaAdapter extends RecyclerView.Adapter<PreguntaAdapter.ViewHolder> {
private Context context;
private ArrayList<VistaEncuestaActivity.PreguntasSiNo> preguntas;
public ArrayList<Respuestas> respuestas = new ArrayList<Respuestas>();
public PreguntaAdapter(Context context, ArrayList<VistaEncuestaActivity.PreguntasSiNo> preguntas) {
this.context = context;
this.preguntas = preguntas;
}
public ArrayList<Respuestas> getCheckedItems() {
return respuestas;
}
#NonNull
#Override
public PreguntaAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
LayoutInflater layoutInflater = LayoutInflater.from(context);
View v = layoutInflater.inflate(R.layout.item_pregunta_sino, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull final PreguntaAdapter.ViewHolder viewHolder, int i) {
final VistaEncuestaActivity.PreguntasSiNo currentPregunta = preguntas.get(i);
//viewHolder.pregunta.setText(currentEncuesta.getString_pregunta());
viewHolder.pregunta.setText(currentPregunta.getQuestion());
viewHolder.myLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
viewHolder.setIsRecyclable(false);
}
#Override
public int getItemCount() {
return preguntas.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public SharedPreferences prefs;
private LinearLayout myLinearLayout;
public TextView pregunta;
public RadioGroup radio_group;
public ViewHolder(#NonNull View itemView) {
super(itemView);
pregunta = (TextView) itemView.findViewById(R.id.pregunta);
radio_group = (RadioGroup) itemView.findViewById(R.id.radio_group_pregunta);
prefs = (SharedPreferences) context.getSharedPreferences("logged", Context.MODE_PRIVATE);
myLinearLayout = (LinearLayout) itemView.findViewById(R.id.myLinearLayout);
}
}
}

Thanks all of you for your responses. Unfortunally any response helped me to solve this issue, i used this function and i added the getItemViewType function to my adapter and it's working well now:
#Override
public int getItemViewType(int position) {
return position;
}
And going to the official google docs i could find the next information:
Return the view type of the item at position for the purposes of view recycling. The default implementation of this method returns 0, making the assumption of a single view type for the adapter. Unlike ListView adapters, types need not be contiguous. Consider using id resources to uniquely identify item view types. https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter
This make sense at the time RecyclerView "recycle" the views but when this is use it in the adapter this have a different behavior treating each view as unique.
Thank you to all of you.

RadioGroup.getCheckedRadioButtonId() is the way to go. In conjunction with a SparseArray<Integer>.
In onBindViewHolder():
On each RadioGroup, set a RadioGroup.OnCheckedChangeListener(). Add the checked state to the a SparseArray or Map<Integer,Integer> mapping the index of the item position to the updated value in RadioGroup.OnCheckedChangeListener() onCheckedChanged.
So your onBindViewHolder would look something like this:
private SparseArray<Integer> mMapping = new SparseArray<>();
public void onBindViewHolder(#NonNull final PreguntaAdapter.ViewHolder viewHolder,final int position) {
final VistaEncuestaActivity.PreguntasSiNo currentPregunta = preguntas.get(i);
//viewHolder.pregunta.setText(currentEncuesta.getString_pregunta());
viewHolder.pregunta.setText(currentPregunta.getQuestion());
viewHolder.myLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
viewHolder.radio_group.setOnCheckedChangeListener(new OnCheckedChangeListener(){
void onCheckedChanged(RadioGroup group,int checked) {
mMapping.put(position,checked);
}
}};
// Check to see if a previous checked value exists and restore.
if(mMapping.get(position) != null && mMapping.get(position) != -1){
radio_group.check(mMapping.get(position));
}
viewHolder.setIsRecyclable(false);
}
onCheckedChanged(RadioGroup group, int checkedId)
You should give each RadioButton a unique ID, like radioButton_1, radioButton_2 in your layout file.

Related

Appropriateness of method for spinner

I know there is no setText() function for Spinner, but I still don't know how to replace it with a more suitable method.
This error pointed out by Android Studio comes from the onBindViewHolder method.
// error: cannot find symbol method setText(String)
holder.spinnerCategory_book.setText(v_book.getCategory_book());
public class BookAdapter extends RecyclerView.Adapter<BookAdapter.ViewHolder> {
List<Book> books;
Context context;
DatabaseHelperClass bd;
public BookAdapter(List<Adapter> books, Context context) {
this.books = books;
this.context = context;
bd = new DatabaseHelperClass(context);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.activity_view_books,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final Book v_book = books.get(position);
holder.textId_book.setText(Integer.toString(v_book.getId_book()));
holder.editTitle_book.setText(v_book.getTitle_book());
holder.editAuthor_book.setText(v_book.getAuthor_book());
holder.spinnerCategory_book.setText(v_book.getCategory_book()); // Line error
holder.editPublisher_book.setText(v_book.getPublisher_book());
holder.editPages_book.setText(Integer.toString(v_book.getPages_book()));
holder.editYear_publication.setText(Integer.toString(v_book.getYear_publication()));
holder.button_update.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String title_book = holder.holder.editTitle_book.getText().toString();
String author_book = holder.editAuthor_book.getText().toString();
String category_book = holder.spinnerCategory_book.getSelectedItem().toString();
String publisher_book = holder.editPublisher_book.getText().toString();
int pages_book = Integer.parseInt(holder.editPages_book.getText().toString());
int year_publication = Integer.parseInt(holder.editYear_publication.getText().toString());
bd.UpdateBook(new Book(v_books.getId_book(),title_book,author_book,
category_book,publisher_book,pages_book,year_publication));
notifyDataSetChanged();
((Activity) context).finish();
context.startActivity(((Activity) context).getIntent());
}
});
holder.button_delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
bd.DeleteBook(v_book.getId_book());
books.remove(position);
notifyDataSetChanged();
}
});
}
#Override
public int getItemCount() {
return books.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
Button button_update, button_delete;
TextView textId_book;
EditText editTitle_book, editAuthor_book, editPublisher_book, editPages_book, editYear_publication;
Spinner spinnerCategory_book;
public ViewHolder(#NonNull View itemView) {
super(itemView);
textId_book = itemView.findViewById(R.id.textId_book);
editTitle_book = findViewById(R.id.editTitle_book);
editAuthor_book = findViewById(R.id.editAuthor_book);
editPublisher_book = findViewById(R.id.editPublisher_book);
editPages_book = findViewById(R.id.editPages_book);
editYear_publication = findViewById(R.id.editYear_publication);
spinnerCategory_book = findViewById(R.id.spinnerspinnerCategory_book);
button_update = itemView.findViewById(R.id.button_update_book);
button_delete = itemView.findViewById(R.id.button_delete_book);
}
}
}
I know there is no setText() function for Spinner, but I still don't know how to replace it with a more suitable method.
1 - Go to the documentation for Spinner.
2 - Scroll down to the section that lists the public methods to see what's available to you, specifically anything starting with "set". If you don't find anything useful, then look at the inherited methods to see what you get from the base class(es).
3 - Discover setSelection which "Sets the currently selected item." based on it's position within the list of items and sounds like what you're trying to do.
4 - Update your code to work with the API you have, not the API you want.
final Book v_book = books.get(position);
// holder.spinnerCategory_book.setText(v_book.getCategory_book()); // Line error
holder.spinnerCategory_book.setSelection(position);

Position of an imageview changing when searching for an item in RecyclerView

I have a RecyclerView in which I have an ImageView for each item in the form of sendEmail icon. Initially, the ImageView is visible but once I click on it, I hide it using setVisibility(View.GONE) and update the Adapter.
Now, when I click on the sendEmail icon, I hide the icon in that position instantly using reportitems.get(position).setStatus("emailsent");. Now, if, before the search operation, the second item had the ImageView visible and first item did not, then after search if the second item were to be the only item that is relevant, then the ImageView does not show up there in the first position. I am using dynamic search where upon inputting a character, the adapter refreshes instantly and shows the updated RecyclerView. How can I fix this issue?
After search, even though SQ 322 should have the sendEmail icon, it does not show up
Activity code
mAdapter.setOnItemClickListener(new ReportAdapter.OnItemClickListener() {
public void onSendEmailClick(int position){
flightNumber=reportitems.get(position).getFlightNumber();
departureDate=reportitems.get(position).getDepartureDate();
FlightClosureStatus flightClosureStatus=new FlightClosureStatus(flightNumber,departureDate,"emailsent");
flightViewModel.updateFlightClosureStatus(flightClosureStatus);
reportitems.get(position).setStatus("emailsent");
mAdapter.notifyDataSetChanged();
}
}
Adapter Code
public class ReportAdapter extends RecyclerView.Adapter<ReportAdapter.ReportViewHolder> {
private ArrayList<ReportItem> reportlist;
private OnItemClickListener mListener;
private Context mContext;
public ReportAdapter(ArrayList<ReportItem> reportlist, Context context) {
this.reportlist = reportlist;
this.mContext = context;
}
public interface OnItemClickListener {
void onSendEmailClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public static class ReportViewHolder extends RecyclerView.ViewHolder {
public TextView departureDate;
public TextView flightNumber;
public ImageView emailView;
public ReportViewHolder(#NonNull View itemView, OnItemClickListener listener, Context context) {
super(itemView);
departureDate = itemView.findViewById(R.id.departureDaterecyclerview);
flightNumber = itemView.findViewById(R.id.flightnumberrecyclerview);
emailView = itemView.findViewById(R.id.sendemailIcon);
emailView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener != null) {
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION) {
listener.onSendEmailClick(position);
}
}
}
});
}
}
#NonNull
#Override
public ReportViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.report_listing_item, parent, false);
ReportViewHolder rvh= new ReportViewHolder(v,mListener,mContext);
return rvh;
}
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull ReportViewHolder holder, int position) {
ReportItem currentItem = reportlist.get(position);
//here i am setting the visibility of the imageview to gone
if(currentItem.getStatus().contentEquals("emailsent")){
holder.emailView.setVisibility(View.GONE);
}
holder.flightNumber.setText(currentItem.getFlightNumber());
holder.departureDate.setText((currentItem.getDepartureDate()));
}
public List<ReportItem> getList() {
return reportlist;
}
}
Replace your onBindViewHolder with below, basically recycler uses items from pool when available, and once the item visibility is GONE and it is never set to VISIBLE again unless you do it
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull ReportViewHolder holder, int position) {
ReportItem currentItem = reportlist.get(position);
//here i am setting the visibility of the imageview to gone
if(currentItem.getStatus().contentEquals("emailsent")){
holder.emailView.setVisibility(View.GONE);
}else{
holder.emailView.setVisibility(View.VISIBLE);
}
holder.flightNumber.setText(currentItem.getFlightNumber());
holder.departureDate.setText((currentItem.getDepartureDate()));
}

How can I do two text blocks in the listView which the first in the left alignment and the second in the right?

How can I set two text blocks in the listView, of which the first is on the left, the other on the right? I am tried to create a new layout with two textViews. But I don't know how I can connect textViews with listView and how I can set texts on textViews. May anybody help me?
I would like to have a list like this
Assuming you have the list and your layout with those 2 textview is ready just use this adapter and set this adapter to recycler view of the activity. let me know if you face any issues
public class CountryCodeAdapter extends RecyclerView.Adapter<CountryCodeAdapter.ViewHolder> {
private CountryCodeActivity activity;
ArrayList<CountryCodeModel> list = new ArrayList<>();
int selected_pos = 0;
public CountryCodeAdapter(CountryCodeActivity activity, ArrayList<CountryCodeModel> list) {
this.activity = activity;
this.list = list;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_country_listing, parent, false);
return new ViewHolder(rootView);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.tv_row_CountryCodeActivity_countrycode.setText(list.get(holder.getAdapterPosition()).getDial());
holder.tv_row_CountryCodeActivity_countryname.setText(list.get(holder.getAdapterPosition()).getName());
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("country_code", list.get(holder.getAdapterPosition()).getDial());
activity.setResult(activity.RESULT_OK, intent);
activity.finish();
}
});
}
#Override
public int getItemCount() {
return list.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tv_row_CountryCodeActivity_countryname,
tv_row_CountryCodeActivity_countrycode;
public ViewHolder(View itemView) {
super(itemView);
tv_row_CountryCodeActivity_countryname = itemView.findViewById(R.id.tv_row_CountryCodeActivity_countryname);
tv_row_CountryCodeActivity_countrycode = itemView.findViewById(R.id.tv_row_CountryCodeActivity_countrycode);
tv_row_CountryCodeActivity_countryname.setTypeface(AppClass.Lato_Regular);
tv_row_CountryCodeActivity_countrycode.setTypeface(AppClass.Lato_Regular);
}
}
}
1)You should use RecyclerView insteaad of listView, and for recyclerView you can achieve what you want with item decorator.
2)But if you have to use ListView(which is less possible case) you can do this by checking list item position and set the corresponding margin to the layout which is not recomended.
3)Also there is another way to achieve this, which is to use different layout resource xml files, but I would not use the last two variants. I would prefer the first.

RecyclerView is messed up when scrolling

As you can see in the screenshot, my project contains a RecyclerView (for categories of food) which contains more RecyclerViews (for the ingredients). But iv'e got a problem, my RecyclerView is messing up the order. I debuged the project and the parameters are just fine but the RecyclerView is displaying them wrong. As you can see in the picture, Fruits ingredients are displayed in the Dairy category.
IngredientSectionAdapter.Java
(the main adapter,which contain more RecyclerViews)
class SectionViewHolder extends RecyclerView.ViewHolder {
private TextView sectionBtn;
private RecyclerView itemRecyclerView;
public SectionViewHolder(View itemView) {
super(itemView);
sectionBtn = (TextView) itemView.findViewById(R.id.text_category);
itemRecyclerView = (RecyclerView) itemView.findViewById(R.id.ingredientsRecycler);
}
}
private Context context;
private ArrayList<IngredientSectionModel> sectionModelArrayList;
ArrayList<IngredientItemAdapter> adapters;
public IngredientSectionAdapter(Context context, ArrayList<IngredientSectionModel> sectionModelArrayList) {
this.context = context;
this.sectionModelArrayList = sectionModelArrayList;
adapters = new ArrayList<IngredientItemAdapter>();
}
#Override
public SectionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.parent_list,null);
return new SectionViewHolder(v);
}
#Override
public void onBindViewHolder(SectionViewHolder holder, int position) {
final IngredientSectionModel sectionModel = sectionModelArrayList.get(position);
holder.itemRecyclerView.setTag(holder.itemRecyclerView.getVisibility());
final RecyclerView sectionList = holder.itemRecyclerView;
holder.sectionBtn.setText(sectionModel.getSectionLabel());
//recycler view for items
holder.itemRecyclerView.setHasFixedSize(true);
holder.itemRecyclerView.setNestedScrollingEnabled(false);
/* set layout manager on basis of recyclerview enum type */
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,1);
adapters.add(new IngredientItemAdapter(context, sectionModel.getItemArrayList()));
int resId = R.anim.grid_layout_animation_from_bottom;
//LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(context, resId);
holder.itemRecyclerView.setLayoutManager(staggeredGridLayoutManager);
holder.itemRecyclerView.setAdapter(adapters.get(position));
//holder.itemRecyclerView.setLayoutAnimation(animation);
//toggle visibilty of inner RecyclerView (ingredients, not categories)
holder.sectionBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (sectionList.getVisibility() == View.VISIBLE){
sectionList.setVisibility(View.GONE);
}
else
{
sectionList.setVisibility(View.VISIBLE);
}
}
});
}
What can cause this?
Every time onBindViewHolder is called you create a new IngredientItemAdapter and add it to your adapters, and then you call holder.itemRecyclerView.setAdapter(adapters.get(position)). However, adapters.get(position) is not the adapter you just created. Your adapter will get bigger and bigger. Try this
IngredientItemAdapter adapter = adapters.get(position);
adapter.setIngredients(sectionModel.getItemArrayList());
holder.itemRecyclerView.setAdapter(adapter);

Android Recycler View select only one image and show tick mark on selected image

I need a solution of how to do the following thing using Android Recycler View.
I have Multiple Images and i need to select only one image like how the radio button works. Now i can select all the images that i have, but i need to restrict the current working behavior to work like the radio button (E.g.) If one is selected the other images that i have should not be selected.
I have tried with the below code but no luck for me. Can anyone rectify the mistake and make the code workable as per my need.
public class StarCountAdapter extends RecyclerView.Adapter<StarCountAdapter.StarCountHolder> {
Context context;
LayoutInflater inflater;
List<StarCount> starCounts = new ArrayList<>();
public StarCountAdapter(Context context, List<StarCount> starCounts) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.starCounts = starCounts;
}
#Override
public StarCountHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.star_count_row,parent,false);
return new StarCountHolder(view);
}
#Override
public void onBindViewHolder(StarCountHolder holder, int position) {
StarCount model = starCounts.get(position);
Picasso.with(context)
.load("http://"+model.getImagePath())
.into(holder.starImage);
holder.actorName.setText(model.getName());
holder.counts.setText(""+model.getCount());
}
#Override
public int getItemCount() {
return starCounts.size();
}
public class StarCountHolder extends RecyclerView.ViewHolder {
ImageView starImage;
TextView actorName,counts;
StarCount modelCount;
public StarCountHolder(View itemView) {
super(itemView);
starImage = (ImageView) itemView.findViewById(R.id.starCountIv);
actorName = (TextView) itemView.findViewById(R.id.acterName);
counts = (TextView) itemView.findViewById(R.id.counts);
}
}
}
help needed to solve this issue since i am struck up for more than a Day. Share thoughts to rectify my Error in the code and rectify my error.
public int selectedPosition = -1
public class StarCountHolder extends RecyclerView.ViewHolder {
ImageView starImage;
TextView actorName,counts;
StarCount modelCount;
public StarCountHolder(View itemView) {
super(itemView);
starImage = (ImageView) itemView.findViewById(R.id.starCountIv);
actorName = (TextView) itemView.findViewById(R.id.acterName);
counts = (TextView) itemView.findViewById(R.id.counts);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedPosition = getLayoutPosition());
notifyDatasetChanged();
}
});
}
}
Now you are done with the selected item position, change it in your binder
#Override
public void onBindViewHolder(StarCountHolder holder, int position) {
StarCount model = starCounts.get(position);
Picasso.with(context)
.load("http://"+model.getImagePath())
.into(holder.starImage);
holder.actorName.setText(model.getName());
holder.counts.setText(""+model.getCount());
if(selectedPosition == position){
// do whatever you want to do to make it selected.
}
}
Now to get the selected item in your activity, you can do something like this...
inside activity
StartCount startC = starCounts.get(adapter.selectedPosition);
hope it helps

Categories

Resources