Saving State of RecyclerView Checkbox - java

I'm a bit new to Android development.
I was wondering how I can save state of checkboxes in a RecyclerView. I know there are existing solutions for this, but I have a list of items in another RecyclerView that uses the same set of checkboxes. When you click an item, it should show all checkboxes and check those previously checked checkboxes for that item.
I have seen posts using SharedPreferences to save the state but I have different checkboxes states for different item click in another RecyclerView and I do not know how to save these different states.
This is the Adapter class for the list of checkboxes named CurrentAddonAdapter.java:
public class CurrentAddonAdapter extends RecyclerView.Adapter<CurrentAddonAdapter.ViewHolder17> {
private Context context;
private ArrayList items3,price3;
private List<AddonList> addonlist1;
private OnItemClickListener17 mOnItemClickListener17;
CurrentAddonAdapter(Context context, ArrayList items3, ArrayList price3,List addonlist1,OnItemClickListener17 onItemClickListener17){
this.context = context;
this.items3 = items3;
this.price3 = price3;
this.addonlist1 = addonlist1;
this.mOnItemClickListener17 = onItemClickListener17;
}
#NonNull
#Override
public ViewHolder17 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.addoncard,parent,false);
return new ViewHolder17(view,mOnItemClickListener17);
}
private SparseBooleanArray selecteditems = new SparseBooleanArray();
#Override
public void onBindViewHolder(#NonNull final CurrentAddonAdapter.ViewHolder17 holder, int position) {
holder.item1.setText(String.valueOf(items3.get(position)));
holder.price1.setText(String.valueOf(price3.get(position)));
final AddonList currentaddon = addonlist1.get(position);
holder.item1.setChecked(selecteditems.get(position));
holder.item1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(holder.item1.isChecked()){
holder.item1.setChecked(true);
mOnItemClickListener17.onItemCheck(currentaddon);
}
else{
holder.item1.setChecked(false);
mOnItemClickListener17.onItemUncheck(currentaddon);
}
}
});
}
#Override
public int getItemCount() {
return items3.size();
}
public class ViewHolder17 extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView price1;
CheckBox item1;
OnItemClickListener17 onItemClickListener17;
public ViewHolder17(#NonNull View itemView, final OnItemClickListener17 onItemClickListener17) {
super(itemView);
item1 = itemView.findViewById(R.id.addoncheck);
price1 = itemView.findViewById(R.id.priceadd);
this.onItemClickListener17 = onItemClickListener17;
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
onItemClickListener17.onItemClick7(getAdapterPosition());
}
}
public interface OnItemClickListener17{
void onItemClick7(int position);
void onItemCheck(AddonList addonList);
void onItemUncheck(AddonList addonList);
}
}
This is the code for the item click. It shows a dialog box with the list of all checkboxes with CardView elements array named items3 and price3
Cursor viewaddon = db.viewalladdon();
while(viewaddon.moveToNext()){
items3.add(viewaddon.getString(2));
price3.add(viewaddon.getString(3));
addonlist1.add(new AddonList(viewaddon.getString(2)));
}
addrecycler.setHasFixedSize(true);
currentAddonAdapter = new CurrentAddonAdapter(getActivity(),items3,price3,addonlist1,this);
addrecycler.setAdapter(currentAddonAdapter);
addrecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
Please, help. I've been trying to find a solution for weeks and I still can't find one. I just really need this for school.

Related

Adding new button and spinner for each button click

In the activity when user click on add client button I want to add new view to the screen which contains a spinner with list of client names retrieved from api and a button that will do some action on click.
So I thought I would use a recycleview and adapter for this but I think I'm wrong
in the activity I have the adapter
private ClientAdapter clientAdapter;
When I retrieve clients name from API I set the adapter as
clientRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
clientAdapter= new clientAdapter(clientList , this , this);
clientRecyclerView.setAdapter(podAdapter);
At this point I don't want the recycle view to render anything until user click on add new client button then I want to display one item that has spinner with client names and a button.
Then if he clicks again on add client button I want to show another spinner and button and so on.
However now I'm having 3 clients so recycleview render 3 view items which make sense.
But what the trick that I should do to achieve my goal?
Here's my adapter
public class ClintsAdapter extends RecyclerView.Adapter<ClintsAdapter.ViewHolder> {
private List<Clients> clientsList;
private EventListener listener;
public ClintsAdapter(List<Clients> clientsList, EventListener listener , Context context) {
this.clientsList = clientsList;
this.EventListener = listener;
}
#NonNull
#Override // To inflate view
public ClintsAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_client, parent, false);
ViewHolder viewHolder = new ViewHolder(view, listener);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ClintsAdapter.ViewHolder holder, int position) {
ClintsAdapter = new ArrayAdapter<Client>(context, R.layout.spinner_text_view, clientsList);
ClintsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
holder.clientSpinner.setAdapter(ClintsAdapter);
holder.clientSpinner.setTitle("Choose client");
}
#Override
public int getItemCount() {
if (clientsList == null)
return 0;
return clientsList.size();
}
public interface PODListener {
void onClick(int position);
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private SearchableSpinner clientSpinner , collectMethodSpinner;
EventListener listener;
public ViewHolder(View itemView, final EventListener listener) {
super(itemView);
this.listener = podListener;
clientSpinner = itemView.findViewById(R.id.spinner_client);
btnComment = itemView.findViewById(R.id.btn_comment);
btnComment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if ( listener != null ) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
listener.onClick(position);
}
}
}
});
}
#Override
public void onClick(View v) {
}
}
}
and here's my list item
From comments:
The problem is I'm passing list of clients to the adapter (size of 3) then the adapter render 3 items. I don't want this behavior I want to have 0 item if user click on add I will render one item and so on
You are using a single ArrayList<Client> for two different purposes:
The list of clients to choose from in the spinner
The number of spinners to display in the RecyclerView.
These are two separate things, so you need two separate lists.
You can do that with just adding integer value for your ClientsAdapter. Set its default value as 0 and create a method for changing it's value. When you want to add new item (new Spinner and Button) use that method and notify your adapter.
Add a new field called count for your ClientsAdapter.
private int count;
Inside constructor assign its value to 0. So on start its value will be 0 and RecyclerView will show nothing.
public ClintsAdapter(List<Clients> clientsList, EventListener listener , Context context){
this.clientsList = clientsList;
this.EventListener = listener;
count = 0;
}
Change getItemCount method's return value. According to your code getItemCount returns size of your List. That List is for Spinner and has no relation with this method. Instead of returning your List's size return count.
#Override
public int getItemCount() {
return count;
}
Create a method for changing count's value. count starts with 0 (assigned it 0 inside constructor) and when you click Button (add new Spinner and Button) this method will change its value.
public void addItem(int count) {
this.count = count;
}
Whenever you click Button simply call addItem method and pass new count value and notify your clientAdapter.
addClient.setOnClickListener(v -> {
int count = clientRecyclerView.getChildCount();
clientAdapter.addItem(count+1);
clientAdapter.notifyItemInserted(count);
});
NOTE: I don't get it why you're setting podAdapter for RecyclerView.
clientRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
clientAdapter= new clientAdapter(clientList , this , this);
clientRecyclerView.setAdapter(podAdapter);
You're creating clientAdapter reference for your ClientsAdapter but while setting adapter for RecyclerView, you're using different reference (podAdapter).
Full code for ClientsAdapter:
public class ClintsAdapter extends RecyclerView.Adapter<ClintsAdapter.ViewHolder> {
private List<Clients> clientsList;
private EventListener listener;
private int count;
public ClintsAdapter(List<Clients> clientsList, EventListener listener , Context context) {
this.clientsList = clientsList;
this.EventListener = listener;
count = 0;
}
#NonNull
#Override // To inflate view
public ClintsAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_client, parent, false);
ViewHolder viewHolder = new ViewHolder(view, listener);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull ClintsAdapter.ViewHolder holder, int position) {
ClintsAdapter = new ArrayAdapter<Client>(context, R.layout.spinner_text_view, clientsList);
ClintsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
holder.clientSpinner.setAdapter(ClintsAdapter);
holder.clientSpinner.setTitle("Choose client");
}
public void addItem(int count) {
this.count = count;
}
#Override
public int getItemCount() {
return count;
}
public interface PODListener {
void onClick(int position);
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private SearchableSpinner clientSpinner , collectMethodSpinner;
EventListener listener;
public ViewHolder(View itemView, final EventListener listener) {
super(itemView);
this.listener = podListener;
clientSpinner = itemView.findViewById(R.id.spinner_client);
btnComment = itemView.findViewById(R.id.btn_comment);
btnComment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if ( listener != null ) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
listener.onClick(position);
}
}
}
});
}
#Override
public void onClick(View v) {
}
}
}

RecyclerView Adapter highlight clicked or current item

As I'm new to android, I'm struggling to highlight Recyclerview clicked or current item. I have tried some workarounds but nothing helps. Basically I want to highlight selected item even after it is coming back from respective Fragment. Please check my code and help me to get done. Thanks.
public class ContentaAdapter extends RecyclerView.Adapter<ContentaAdapter.MyViewHolder> {
Context context;
ArrayList<String> ItemTitle;
ArrayList<String> ItemSource;
public ContentaAdapter(Context context, ArrayList<String> ItemTitle, ArrayList<String> ItemSource) {
this.context = context;
this.ItemTitle = ItemTitle;
this.ItemSource = ItemSource;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_items_layout, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.ItemTitle.setText(ItemTitle.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Fragment contentdisplay = new ViewContentFragment();
Bundle bundle=new Bundle();
bundle.putStringArrayList("ItemTitle",ItemTitle);
bundle.putStringArrayList("ItemSource",ItemSource);
bundle.putInt("position",position);
bundle.putInt("ItemCounts",ItemTitle.size());
contentdisplay.setArguments(bundle);
((MainActivity)context).replaceFragment(contentdisplay);
}
});
}
#Override
public int getItemCount() {
return ItemTitle.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView ItemTitle;
public MyViewHolder(View itemView) {
super(itemView);
ItemTitle = (TextView) itemView.findViewById(R.id.item_title);
}
}
}
you need to to add isSelected state in to your list item data model and change it onClick.
And when you know state you can change background in ViewHolder
if (isSelected) {
// set selected background here
} else {
// set not selected background here
}
And instead of keeping two lists in adapter you should create one with model ArrayList<DataModel> similar to this:
class DataModel {
String ItemTitle;
String ItemSource;
Boolean isSelected;
}
also you shouldn't pass both list to other fragment, instead take only what you need, for example yourList.get(position);

Update recyclerview single row data when spinner item data is changed

I have a RecyclerView as given in picture below.
I get the food item data from the server and bind them to RecyclerView as above.
Food items are assigned in foodItemList array list which has foodItemTypeList array. In foodItemTypeList array list, values of types and their corresponding prices are stored.
What I want is when the user selects a food type (for example medium), the corresponding unit price is updated.
Here is the FoodItemAdapter class:
public class FoodItemAdapter extends RecyclerView.Adapter<FoodItemAdapter.CustomViewHolder> {
private List<FoodItem> foodItemList;
Context context;
String token;
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView food_name, food_unit_price;
Spinner food_item_type;
public ImageView food_item_image;
public Button viewDetail;
public CustomViewHolder(View view) {
super(view);
food_name = (TextView) itemView.findViewById(R.id.food_name);
food_item_type = (Spinner) itemView.findViewById(R.id.food_item_type);
viewDetail = (Button) itemView.findViewById(R.id.viewDetail);
food_unit_price = (TextView) itemView.findViewById(R.id.food_unit_price);
food_item_image = (ImageView) itemView.findViewById(R.id.food_item_image);
}
}
public FoodItemAdapter(Context context, List<FoodItem> foodItemList,String token) {
this.foodItemList = foodItemList;
this.context = context;
this.token = token;
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.food_items_item, parent, false);
return new CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(final CustomViewHolder holder, int position) {
FoodItem foodItem = foodItemList.get(position);
holder.food_name.setText(foodItem.getFood_name());
holder.viewDetail.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
}
});
holder.food_unit_price.setText(foodItem.getFood_unit_price()+" AF");
if(foodItem.getFood_item_image()!=null && !foodItem.getFood_item_image().isEmpty()){
Picasso.get()
.load(foodItem.getFood_item_image())
// To fit image into imageView
.resize(50, 50)
.centerCrop()
.into(holder.food_item_image);
} else {
Log.d("Food Item Image:", "Food Item image is either empty or null");
}
List<FoodItemType> foodItemTypeList = new ArrayList<>();
foodItemTypeList = foodItem.getFoodItemTypeList();
ArrayAdapter userAdapter = new ArrayAdapter(context, R.layout.spinner, foodItemTypeList);
holder.food_item_type.setAdapter(userAdapter);
holder.food_item_type.setOnItemSelectedListener(new
AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int
position, long id) {
FoodItemType foodItemType = (FoodItemType) (holder.food_item_type).getSelectedItem();
Toast.makeText(context, "Clicked: " +
foodItemType.getFood_unit_price(), Toast.LENGTH_LONG).show();
FoodItem foodItemNew = new FoodItem(foodItemList.get(holder.getAdapterPosition()).getFood_item_id(),foodItemList.get(holder.getAdapterPosition()).getFood_category_id(),foodItemList.get(holder.getAdapterPosition()).getFood_name(),foodItemList.get(holder.getAdapterPosition()).getFood_item_image(),foodItemList.get(holder.getAdapterPosition()).getFood_item_desc(), foodItemType.getFood_item_type_id(),foodItemType.getFood_item_type_name(),foodItemType.getFood_unit_price(), foodItemList.get(holder.getAdapterPosition()).getFoodItemTypeList());
foodItemList.set(holder.getAdapterPosition(),foodItemNew);
notifyItemChanged(holder.getAdapterPosition());
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// todo for nothing selected
}
});
}
#Override
public int getItemCount() {
return foodItemList.size();
}
}
A part of my FoodItemsFragment class is as below:
recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_food_item);
foodItemAdapter = new FoodItemAdapter(getActivity(),foodItemList, token);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(foodItemAdapter);
foodItemAdapter.notifyDataSetChanged();
My problem is: When I scroll RecyclerView, the view is loaded multiple times (a kind of lagging) and when I change the foody type (for example: to medium), nothing happens.
Any kind of help is appreciated.
I would like to suggest you have another field in your FoodItem class, which is selectedFoodType. This will hold the index of the type selected. By default, initialize the value with 0 and when an item is selected from the drop-down list, just update the corresponding FoodItem's selectedFoodType accordingly.
Another thing is, you do not have to create a new FoodItem each time you are changing the type of the FoodItem. You need to have the selectedFoodType only and then call the notifyDataSetChanged().
So the code should look like the following. Inside your onItemSelected function, do the following.
int foodType = foodItemTypeList.get(position);
FoodItem foodItem = foodItemNew.get(holder.getAdapterPosition());
foodItem.setSelectedFoodType = foodType;
notifyDataSetChanged();
Please note that I have not tested this code. Please modify as per your need. Hope that helps!

Select only one image in RecyclerView

I have a RecyclerView.Adapter which has some Arrays there.
ArrayList with Strings and ArrayList with Integer. Strings are like url and Integer is the photo.
When the app is open for first time the first item is selected.
I have another method for click which makes another item as selected and this works, but the problem is that the first item stays as selected and so for every image click makes as selected, I want only one item to be selected and take a color.
This is my code.
Adapter of RecyclerView
public class ListViewAdapter extends RecyclerView.Adapter<ListViewAdapter.ViewHolder>{
private int selectedItem;
private ArrayList<Integer> mImages = new ArrayList<>();
private ArrayList<String> mSearchUrl = new ArrayList<>();
private Context mContext;
public ListViewAdapter(ArrayList<Integer> images, ArrayList<String> SearchUrl, Context context) {
mImages = images;
mContext = context;
mSearchUrl = SearchUrl;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.s_engine_item, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder viewHolder, final int i) {
selectedItem = 0;
if (selectedItem == i) {
viewHolder.image.setBackgroundColor(Color.parseColor("#30000000"));
}
Glide.with(mContext).load(mImages.get(i))
.into(viewHolder.image);
viewHolder.searchUrl.setText(mSearchUrl.get(i));
viewHolder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.image.setBackgroundColor(Color.parseColor("#30000000"));
selectedItem = i;
}
});
}
#Override
public int getItemCount() {
return mImages.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView image;
TextView searchUrl;
public ViewHolder(#NonNull View itemView) {
super(itemView);
image = itemView.findViewById(R.id.ivEngine);
searchUrl = itemView.findViewById(R.id.ivEngineText);
}
}
}
And this is the MainActivity.class
public void intSearch() {
mImages.add(R.drawable.s_bing);
mSearchUrl.add("https://www.bing.com/search?q=");
mImages.add(R.drawable.s_google);
mSearchUrl.add("https://www.google.com/search?q=");
mImages.add(R.drawable.s_yahoo);
mSearchUrl.add("www.yahoo.com");
mImages.add(R.drawable.amazon_white256);
mSearchUrl.add("www.amazon.com");
mImages.add(R.drawable.amazon_white256);
mSearchUrl.add("www.amazon.com");
mImages.add(R.drawable.amazon_white256);
mSearchUrl.add("www.amazon.com");
initRecyclerView();
}
private void initRecyclerView() {
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
RecyclerView recyclerView = findViewById(R.id.lvEngines);
recyclerView.setLayoutManager(layoutManager);
ListViewAdapter adapter = new ListViewAdapter(mImages, mSearchUrl, this);
recyclerView.setAdapter(adapter);
}
Initialize your selected item globally
public class ListViewAdapter extends RecyclerView.Adapter<ListViewAdapter.ViewHolder>{
private int selectedItem = 0;
.....
Then inside your onBindViewHolder whenever you click a new Image notify your adapter for changes in the last selected item cell.
viewHolder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int previousSelectedItem = selectedItem;
selectedItem = i;
notifyItemChanged(previousSelectedItem);
viewHolder.image.setBackgroundColor(Color.parseColor("#30000000"));
}
});
Just remove this line from onBindViewHolder
selectedItem = 0;
and add an else to the background condition, like:
if (selectedItem == i) {
viewHolder.image.setBackgroundColor(Color.parseColor("#30000000"));
}else{
viewHolder.image.setBackgroundColor(“YOUR_DEFAULT_COLOR”);
}
and update the onClick:
viewHolder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedItem = i;
notifyDataSetChanged();
}
});

Redraw RecyclerView After A Touch Event

I have a RecycleView Which shows a bunch of list in which one item is selected by showing its background color blue, now I want user to select any item from list and its color get changed to blue how to implement this inside RecyclerView.Adapter or any other logic
public class ToggleAdapter extends RecyclerView.Adapter<ToggleAdapter.ToggleViewHolder>{
private ArrayList<ToggleParams> dataList=new ArrayList<>();
private Context context;
private static int selection;
public ToggleAdapter(ArrayList<ToggleParams> dataList, Context context,int selection) {
setData(dataList,context,selection);
}
#Override
public ToggleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_row,parent,false);
ToggleViewHolder toggleViewHolder=new ToggleViewHolder(v);
return toggleViewHolder;
}
#Override
public void onBindViewHolder(ToggleViewHolder holder, int position) {
if(position==selection){
holder.selected_item.setBackgroundColor(context.getResources().getColor(R.color.blue));
holder.text_view.setTextColor(context.getResources().getColor(android.R.color.white));
}
holder.image_view.setImageDrawable(context.getResources().getDrawable(dataList.get(position).getIMAGE_ID()));
holder.text_view.setText(dataList.get(position).getTOGGLE_TEXT());
}
private void setData(ArrayList<ToggleParams> dataList, Context context,int selection) {
this.dataList = dataList;
this.context = context;
this.selection = selection;
}
#Override
public int getItemCount() {
return dataList.size();
}
public static class ToggleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public LinearLayout selected_item;
public ImageView image_view;
public TextView text_view;
public ToggleViewHolder(View itemView) {
super(itemView);
selected_item= (LinearLayout) itemView.findViewById(R.id.selected_item);
selected_item.setOnClickListener(this);
image_view= (ImageView) itemView.findViewById(R.id.imageView);
text_view= (TextView) itemView.findViewById(R.id.textView);
}
public void onClick(View v) {
selection=getPosition();
//After getting this position I want that this item list in recyclerview to change its background color but how to call notifyDataSetChange() here something equivalent to that
}
}
}
You can use the setOnCLickListener in onBindViewHolder and can call notifyDatasetChanged there or a better way is to define an interface which gets called on when an itemView is clicked and to instantiate it in the adapter. For example see the following answer
Why doesn't RecyclerView have onItemClickListener()? And how RecyclerView is different from Listview?

Categories