I want to loop through all CardViews and change the text and color of a TextView within a single CardView item using a button click. The following code seems to produce the desired results but I'm not certain that it's the most effective code or even accurate (index).
// CustomAdapter
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class CustomAdapter extends RecyclerView.Adapter<CustomViewHolder> {
private Context context;
private List<MyModel> list;
public CustomAdapter(Context context, List<MyModel> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(context).inflate(R.layout.single_items, parent, false));
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
holder.textName.setText(list.get(position).getName());
holder.textAge.setText(String.valueOf(list.get(position).getAge()));
}
#Override
public int getItemCount() {
return list.size();
}
}
//CustomViewHolder
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView textName, textAge;
public CustomViewHolder(#NonNull View itemView) {
super(itemView);
textName = itemView.findViewById(R.id.textName);
textAge = itemView.findViewById(R.id.textAge);
}
}
MainActivity
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
List<MyModel> myModelList;
CustomAdapter customAdapter;
private Button button1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
}
private void loadData() {
recyclerView = findViewById(R.id.recycler_main);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(this, 1));
myModelList = new ArrayList<>();
myModelList.add(new MyModel("Joe", 21));
myModelList.add(new MyModel("Jane", 26));
myModelList.add(new MyModel("Kyle", 19));
myModelList.add(new MyModel("Scott", 30));
customAdapter = new CustomAdapter(this, myModelList);
recyclerView.setAdapter(customAdapter);
}
public void onClickBtn(View v)
{
String searchString = "Kyle";
for (int x = recyclerView.getChildCount(), i = 0; i < x; ++i) {
RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i));
TextView txtName = holder.itemView.findViewById(R.id.textName);
if (txtName.getText().toString().equals(searchString.toString())) {
txtName.setText("Found " + txtName.getText().toString());
txtName.setTextColor(Color.GREEN);
customAdapter.notifyItemChanged(x);
}
}
}
}
//MyModel
public class MyModel {
String name = "";
int age = 0;
public MyModel(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
It's important that I iterate through the list in button click event. Functionality to be changed later. Really appreciate any advice and feedback. Update. Must be an index or other related problem. When my ArrayList contains many, many more items and button is clicked, a lot of non found rows text and color are changed.
Try this adapter:
public class CustomAdapter extends RecyclerView.Adapter<CustomViewHolder> {
private Context context;
private List<MyModel> list;
private String searchString = "";
public CustomAdapter(Context context, List<MyModel> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(context).inflate(R.layout.single_items, parent, false));
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
holder.textAge.setText(String.valueOf(list.get(position).getAge()));
if(list.get(position).getName().equals(searchString)){
holder.textName.setText("Found " + list.get(position).getName());
holder.textName.setTextColor(Color.GREEN);
} else {
holder.textName.setText(list.get(position).getName());
holder.textName.setTextColor(Color.BLACK);
}
}
#Override
public int getItemCount() {
return list.size();
}
public void setNewSearchString(String searchString) {
this.searchString = searchString;
notifyDataSetChanged();
}
}
and button click:
public void onClickBtn(View v)
{
customAdapter.setNewSearchString("Kyle");
}
For Multiple search, the adapter:
public class CustomAdapter extends RecyclerView.Adapter<CustomViewHolder> {
private Context context;
private List<MyModel> list;
//private String searchString = "";
private ArrayList<String> arraySearchStrings = new ArrayList<>();
public CustomAdapter(Context context, List<MyModel> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(context).inflate(R.layout.single_items, parent, false));
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
holder.textAge.setText(String.valueOf(list.get(position).getAge()));
boolean found = false;
for (String searchString : arraySearchStrings) {
if (list.get(position).getName().equals(searchString)) {
found = true;
break;
}
}
if (found) {
holder.textName.setText("Found " + list.get(position).getName());
holder.textName.setTextColor(Color.GREEN);
} else {
holder.textName.setText(list.get(position).getName());
holder.textName.setTextColor(Color.BLACK);
}
}
#Override
public int getItemCount() {
return list.size();
}
public void setNewSearchString(String searchString) {
//this.searchString = searchString;
arraySearchStrings.add(searchString);
notifyDataSetChanged();
}
public void resetSearchString() {
arraySearchStrings.clear();
notifyDataSetChanged();
}
}
Button click:
public void onClickBtn(View v)
{
customAdapter.setNewSearchString("Kyle");
customAdapter.setNewSearchString("Steve");
customAdapter.setNewSearchString("Joe");
}
Alternative answser:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {
private Context context;
private List<MyModel> list;
private ArrayList<String> arraySearchStrings = new ArrayList<>();
private ArrayList<Boolean> arrayFound = new ArrayList<>();
private int[] arrayFoundCount;
private int foundTotalCount = 0;
public CustomAdapter(Context context, List<MyModel> list) {
this.context = context;
this.list = list;
arrayFoundCount = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
arrayFound.add(false);
arrayFoundCount[i] = 0;
}
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(context).inflate(R.layout.single_items, parent, false));
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
holder.textAge.setText(String.valueOf(list.get(position).getAge()));
holder.textCount.setText(String.valueOf(arrayFoundCount[position]));
if (arrayFound.get(position)) {
holder.textName.setText("Found " + list.get(position).getName());
holder.textName.setTextColor(Color.GREEN);
} else {
holder.textName.setText(list.get(position).getName());
holder.textName.setTextColor(Color.BLACK);
}
}
#Override
public int getItemCount() { return list.size(); }
public class CustomViewHolder extends RecyclerView.ViewHolder {
public TextView textName, textAge, textCount;
public CustomViewHolder(#NonNull View itemView) {
super(itemView);
textName = itemView.findViewById(R.id.textName);
textAge = itemView.findViewById(R.id.textAge);
textCount = itemView.findViewById(R.id.textCount);
}
}
private int countFoundNameInList() {
int count = 0;
boolean found;
MyModel model;
arrayFound.clear();
for (int i = 0; i < list.size(); i++) {
model = list.get(i);
found = false;
for (String searchString : arraySearchStrings) {
if (model.getName().equals(searchString)) {
found = true;
arrayFoundCount[i] = arrayFoundCount[i]++;
count++;
break;
}
}
arrayFound.add(found);
}
return count;
}
public void setNewSearchString(String searchString) {
arraySearchStrings.add(searchString);
int newCount = countFoundNameInList();
if (newCount > foundTotalCount) {
Toast.makeText(context, searchString + " found.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Error: Nothing found!!", Toast.LENGTH_LONG).show();
}
foundTotalCount = newCount;
notifyDataSetChanged();
}
}
I don't think this code will give you accurate result.
you have to come up with different logic for this
In your logic you are searching static name i am sure this is for demo purpose only. later you will implement with user input string.
So As per my opinion you can create variable in your adapter that search mode is on or off
after this when ever user start searching make searchMode On and same as when they done with searching set searchMode Off
in your viewHolder Class you can update View on searchMode on off Status.
You can Create 2 list
1 is for main List
seconds is for searched list
when user starts searching you have to filter main list with search string and then set it to searchedList and also make searchMode On and then update it to your adapter. rest will handle your adapter. no need to change it one by one from your list.
I am adding here required changes as per my opinion
Your Custom Adapter
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {
private Context context;
private List<MyModel> list;
private Boolean isSearchModeOn = false;
public CustomAdapter(#NonNull Context context, #NonNull List<MyModel> list) {
this.context = context;
this.list = list;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CustomViewHolder(LayoutInflater.from(context).inflate(R.layout.single_items, parent, false));
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
if (isSearchModeOn){
holder.textName.setText("Found " + list.get(position).getName());
holder.textName.setTextColor(Color.GREEN);
}else {
holder.textName.setText(list.get(position).getName());
//Also set Here normal text color
}
holder.textAge.setText(String.valueOf(list.get(position).getAge()));
}
#SuppressLint("NotifyDataSetChanged")
public void updateList(#NonNull List<MyModel> searchedList){
list = searchedList;
notifyDataSetChanged();
}
#SuppressLint("NotifyDataSetChanged")
public void setSearchMode(#NonNull Boolean isOn){
isSearchModeOn = isOn;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return list.size();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
#NonNull
public TextView textName, textAge;
public CustomViewHolder(#NonNull View itemView) {
super(itemView);
textName = itemView.findViewById(R.id.textName);
textAge = itemView.findViewById(R.id.textAge);
}
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
List<MyModel> myModelList;
List<MyModel> searchedList;
CustomAdapter customAdapter;
#Override
protected void onCreate(#NonNull Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
loadData();
}
private void loadData() {
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(this, 1));
myModelList = new ArrayList<>();
myModelList.add(new MyModel("Joe", 21));
myModelList.add(new MyModel("Jane", 26));
myModelList.add(new MyModel("Kyle", 19));
myModelList.add(new MyModel("Scott", 30));
customAdapter = new CustomAdapter(this, myModelList);
recyclerView.setAdapter(customAdapter);
}
public void onClickBtn(#NonNull View v)
{
String searchString = "Kyle";
searchedList = new ArrayList<>();
for (int x = myModelList.size(), i = 0; i < x; ++i) {
if (myModelList.get(i).getName().equals(searchString)){
searchedList.add(myModelList.get(i));
}
}
customAdapter.updateList(searchedList);
customAdapter.setSearchMode(true);
}
}
I am mostly develop in kotlin so maybe some text error can happen in this code. you can check the logic for this requirement
Related
I try to implement expandable RecyclerView as shown in this example :
https://github.com/CodingSTUFF070/Nested-RecyclerView-Inside-Expandable-RecyclerView
But I have bug :
When I implement the same for my app. Steps to reproduce - Click 1st item (Instant Food and Noodles) and scroll to last and click last item (Personal Care) without closing 1st opened item. Now, if you scroll-up and see the child items of 1st parent, you'll see child items of lastly opened parent (Personal Care).
Please tell me how to fix this?
MainActivity:
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<DataModel> mList;
private ItemAdapter adapter;
private Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = findViewById(R.id.main_recyclervie);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mList = new ArrayList<>();
//list1
List<String> nestedList1 = new ArrayList<>();
nestedList1.add("Jams and Honey");
nestedList1.add("Pickles and Chutneys");
nestedList1.add("Readymade Meals");
nestedList1.add("Chyawanprash and Health Foods");
nestedList1.add("Pasta and Soups");
nestedList1.add("Sauces and Ketchup");
nestedList1.add("Namkeen and Snacks");
nestedList1.add("Honey and Spreads");
List<String> nestedList2 = new ArrayList<>();
nestedList2.add("Book");
nestedList2.add("Pen");
nestedList2.add("Office Chair");
nestedList2.add("Pencil");
nestedList2.add("Eraser");
nestedList2.add("NoteBook");
nestedList2.add("Map");
nestedList2.add("Office Table");
List<String> nestedList3 = new ArrayList<>();
nestedList3.add("Decorates");
nestedList3.add("Tea Table");
nestedList3.add("Wall Paint");
nestedList3.add("Furniture");
nestedList3.add("Bedsits");
nestedList3.add("Certain");
nestedList3.add("Namkeen and Snacks");
nestedList3.add("Honey and Spreads");
List<String> nestedList4 = new ArrayList<>();
nestedList4.add("Pasta");
nestedList4.add("Spices");
nestedList4.add("Salt");
nestedList4.add("Chyawanprash");
nestedList4.add("Maggie");
nestedList4.add("Sauces and Ketchup");
nestedList4.add("Snacks");
nestedList4.add("Kurkure");
List<String> nestedList5 = new ArrayList<>();
nestedList5.add("Jams and Honey");
nestedList5.add("Pickles and Chutneys");
nestedList5.add("Readymade Meals");
nestedList5.add("Chyawanprash and Health Foods");
nestedList5.add("Pasta and Soups");
nestedList5.add("Sauces and Ketchup");
nestedList5.add("Namkeen and Snacks");
nestedList5.add("Honey and Spreads");
List<String> nestedList6 = new ArrayList<>();
nestedList6.add("Pasta");
nestedList6.add("Spices");
nestedList6.add("Salt");
nestedList6.add("Chyawanprash");
nestedList6.add("Maggie");
nestedList6.add("Sauces and Ketchup");
nestedList6.add("Snacks");
nestedList6.add("Kurkure");
List<String> nestedList7 = new ArrayList<>();
nestedList7.add("Decorates");
nestedList7.add("Tea Table");
nestedList7.add("Wall Paint");
nestedList7.add("Furniture");
nestedList7.add("Bedsits");
nestedList7.add("Certain");
nestedList7.add("Namkeen and Snacks");
nestedList7.add("Honey and Spreads");
mList.add(new DataModel(nestedList1 , "Instant Food and Noodles"));
mList.add(new DataModel( nestedList2,"Stationary"));
mList.add(new DataModel( nestedList3,"Home Care"));
mList.add(new DataModel(nestedList4 ,"Grocery & Staples"));
mList.add(new DataModel(nestedList5,"Pet Care"));
mList.add(new DataModel(nestedList6,"Baby Care"));
mList.add(new DataModel(nestedList7 ,"Personal Care"));
adapter = new ItemAdapter(mList);
recyclerView.setAdapter(adapter);
}
}
DataModel:
public class DataModel {
private List<String> nestedList;
private String itemText;
private boolean isExpandable;
public DataModel(List<String> itemList, String itemText) {
this.nestedList = itemList;
this.itemText = itemText;
isExpandable = false;
}
public void setExpandable(boolean expandable) {
isExpandable = expandable;
}
public List<String> getNestedList() {
return nestedList;
}
public String getItemText() {
return itemText;
}
public boolean isExpandable() {
return isExpandable;
}
}
ItemAdapter:
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ItemViewHolder> {
private List<DataModel> mList;
private List<String> list = new ArrayList<>();
public ItemAdapter(List<DataModel> mList){
this.mList = mList;
}
#NonNull
#Override
public ItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.each_item , parent , false);
return new ItemViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ItemViewHolder holder, int position) {
DataModel model = mList.get(position);
holder.mTextView.setText(model.getItemText());
boolean isExpandable = model.isExpandable();
holder.expandableLayout.setVisibility(isExpandable ? View.VISIBLE : View.GONE);
if (isExpandable){
holder.mArrowImage.setImageResource(R.drawable.arrow_up);
}else{
holder.mArrowImage.setImageResource(R.drawable.arrow_down);
}
NestedAdapter adapter = new NestedAdapter(list);
holder.nestedRecyclerView.setLayoutManager(new LinearLayoutManager(holder.itemView.getContext()));
holder.nestedRecyclerView.setHasFixedSize(true);
holder.nestedRecyclerView.setAdapter(adapter);
holder.linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
model.setExpandable(!model.isExpandable());
list = model.getNestedList();
notifyItemChanged(holder.getAdapterPosition());
}
});
}
#Override
public int getItemCount() {
return mList.size();
}
public class ItemViewHolder extends RecyclerView.ViewHolder{
private LinearLayout linearLayout;
private RelativeLayout expandableLayout;
private TextView mTextView;
private ImageView mArrowImage;
private RecyclerView nestedRecyclerView;
public ItemViewHolder(#NonNull View itemView) {
super(itemView);
linearLayout = itemView.findViewById(R.id.linear_layout);
expandableLayout = itemView.findViewById(R.id.expandable_layout);
mTextView = itemView.findViewById(R.id.itemTv);
mArrowImage = itemView.findViewById(R.id.arro_imageview);
nestedRecyclerView = itemView.findViewById(R.id.child_rv);
}
}
}
NestedAdapter:
public class NestedAdapter extends RecyclerView.Adapter<NestedAdapter.NestedViewHolder> {
private List<String> mList;
public NestedAdapter(List<String> mList){
this.mList = mList;
}
#NonNull
#Override
public NestedViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.nested_item , parent , false);
return new NestedViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull NestedViewHolder holder, int position) {
holder.mTv.setText(mList.get(position));
}
#Override
public int getItemCount() {
return mList.size();
}
public class NestedViewHolder extends RecyclerView.ViewHolder{
private TextView mTv;
public NestedViewHolder(#NonNull View itemView) {
super(itemView);
mTv = itemView.findViewById(R.id.nestedItemTv);
}
}
}
As I fetched and show the dates (see image) as the title of the main recyclerview. I want to show the available slots data instead of the 0 1 2 etc elements. The code is attached below
Url for json data
https://run.mocky.io/v3/c9bd7858-0e41-422f-b1d2-cd490c08583b
AppointmentTimeActivity.java
public class AppointmentTimeActivity extends AppCompatActivity {
SharedPrefManager sharedPrefManager;
Button appointmentTimeButton;
private TextView doctorFullName;
ConstraintLayout constraintLayout;
public static List<List<String>> availableSlots;
RecyclerView rvGroup;
public static ArrayList<String> arrayListGroup;
LinearLayoutManager layoutManagerGroup;
GroupAdapter groupAdapter;
private DoctorScheduleResponse timings;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_appointment_time);
getSupportActionBar().setTitle("Appointment time");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
sharedPrefManager = new SharedPrefManager(this);
constraintLayout = findViewById(R.id.constraintLayout);
appointmentTimeButton = findViewById(R.id.book_video_call_appointment_btn);
doctorFullName = findViewById(R.id.doctor_full_name);
rvGroup = findViewById(R.id.rv_group);
String docName = getIntent().getStringExtra("doctorFullName");
doctorFullName.setText(docName);
arrayListGroup = new ArrayList<>();
fetchAndShowAppointmentsTime();
}
private void fetchAndShowAppointmentsTime() {
String id = String.valueOf(SpecialityActivity.doctorID);
Call<DoctorScheduleResponse> call = RetrofitClient.getInstance().getMyInterface().getAppointmentTime("Bearer " + sharedPrefManager.getAccessToken(), id);
call.enqueue(new Callback<DoctorScheduleResponse>() {
#Override
public void onResponse(#NotNull Call<DoctorScheduleResponse> call, #NotNull Response<DoctorScheduleResponse> response) {
arrayListGroup = new ArrayList<>();
if (response.isSuccessful()) {
assert response.body() != null;
for (List<Slot> slots : response.body().getSlot()) {
for (Slot slot : slots) {
arrayListGroup.add(slot.getScheduleDate());
}
}
groupAdapter = new GroupAdapter(AppointmentTimeActivity.this, response.body().getSlot());
layoutManagerGroup = new LinearLayoutManager(getApplicationContext());
rvGroup.setLayoutManager(layoutManagerGroup);
rvGroup.setAdapter(groupAdapter);
}
}
#Override
public void onFailure(#NotNull Call<DoctorScheduleResponse> call, #NotNull Throwable t) {
Toast.makeText(getBaseContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
DoctorScheduleResponse.java
public class DoctorScheduleResponse {
#SerializedName("slot")
#Expose
private List<List<Slot>> slot = null;
public List<List<Slot>> getSlot() {
return slot;
}
public void setSlot(List<List<Slot>> slot) {
this.slot = slot;
}
}
GroupAdater.java
public class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.ViewHolder> {
private Activity activity;
ArrayList<String> arrayListGroup, arrayListMember;
LinearLayoutManager linearLayoutManager;
SharedPrefManager sharedPrefManager;
List<List<Slot>> slotsList;
public GroupAdapter(Activity activity, ArrayList<String> arrayListGroup) {
this.activity = activity;
this.arrayListGroup = arrayListGroup;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.custom_slot_layout, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.dummyTV.setText(arrayListGroup.get(position));
arrayListMember = new ArrayList<>();
sharedPrefManager = new SharedPrefManager(activity);
for (int i = 0; i < 5; i++) {
arrayListMember.add(String.valueOf(i));
}
CustomAdapter customAdapter = new CustomAdapter(arrayListMember);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(activity);
holder.rvMember.setLayoutManager(linearLayoutManager);
holder.rvMember.setAdapter(customAdapter);
}
#Override
public int getItemCount() {
return arrayListGroup.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView dummyTV;
RecyclerView rvMember;
public ViewHolder(#NonNull View itemView) {
super(itemView);
dummyTV = itemView.findViewById(R.id.dummyTextView);
rvMember = itemView.findViewById(R.id.rv_member);
}
}
}
CustomAdapter.java
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.SlotsViewHolder> {
ArrayList<String> slots;
public CustomAdapter(ArrayList<String> slots) {
this.slots = slots;
}
#NonNull
#Override
public SlotsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.available_slots_list, parent, false);
return new CustomAdapter.SlotsViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull SlotsViewHolder holder, int position) {
holder.tvSlots.setText(slots.get(position));
}
#Override
public int getItemCount() {
return slots.size();
}
public class SlotsViewHolder extends RecyclerView.ViewHolder {
TextView tvSlots;
public SlotsViewHolder(#NonNull View itemView) {
super(itemView);
tvSlots = itemView.findViewById(R.id.tv_slots);
}
}
}
Nested recycler view will be more complex in terms of memory. So you can achieve same UI with different approach.
You should try with single recycler view with dynamic layout binding.
Example: For single item of recycler view, there will be a header(for date) and a viewgroup(may be linear layout) then bind any no. of child views inside that linear layout.
The problem is in GroupAdater.java. Inside onBindViewHolder method you are adding the value of loop variable to your list that you pass to your nested recycler view adaptor.
for (int i = 0; i < 5; i++) {
arrayListMember.add(String.valueOf(i));
}
You have to add the correct date from arrayListGroup object.
Here you can see I have plist in which I'm fetching the selected checkboxes when user clicks on select all button.
Here is that when I show the list of data. There is only the data of those checkboxes which are visible on screen and when I scroll down, remaining checkboxes get selected and when I scroll some more time it another repeated values of selected checkboxes
Adapter.java
public class AttendanceRegisterAdapter extends RecyclerView.Adapter<AttendanceRegisterAdapter.AttendanceViewHolder> {
Context context;
private ArrayList<Student> student;
private boolean isSelectedAll;
private ArrayList<String> plist = new ArrayList<>();
public AttendanceRegisterAdapter(Context context, ArrayList<Student> student) {
this.context = context;
this.student = student;
}
#NonNull
#Override
public AttendanceViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.template_card_student, parent, false);
return new AttendanceViewHolder(view);
}
public void selectAll() {
isSelectedAll = true;
notifyDataSetChanged();
}
public void unSelectAll() {
isSelectedAll = false;
notifyDataSetChanged();
}
#Override
public void onBindViewHolder(#NonNull AttendanceViewHolder holder, int position) {
final Student selectedList = student.get(position);
holder.cbAttendance.setSelected(selectedList.getSelected());
holder.cbAttendance.setTag(position);
if (isSelectedAll) {
selectedList.setSelected(true);
plist.add(student.get(position).getStudentID());
} else {
selectedList.setSelected(false);
plist.remove(student.get(position).getStudentID());
}
holder.cbAttendance.setChecked(selectedList.getSelected());
}
#Override
public int getItemCount() {
return student.size();
}
class AttendanceViewHolder extends RecyclerView.ViewHolder {
CardView cvStudentCard;
ImageView imgStudentPicture;
TextView txtStudentName;
CheckBox cbAttendance;
public AttendanceViewHolder(#NonNull View itemView) {
super(itemView);
cvStudentCard = itemView.findViewById(R.id.card_student_view);
imgStudentPicture = itemView.findViewById(R.id.img_student_picture);
txtStudentName = itemView.findViewById(R.id.tv_card_title);
cbAttendance = itemView.findViewById(R.id.cb_attendance);
}
}
}
You are adding StudentId in BindViewHolder without checking plist
maybe duplicate values are added each time BindViewHolder is called.
public class AttendanceRegisterAdapter extends RecyclerView.Adapter<AttendanceRegisterAdapter.AttendanceViewHolder> {
Context context;
private ArrayList<Student> student;
private boolean isSelectedAll;
private ArrayList<String> plist = new ArrayList<>();
public AttendanceRegisterAdapter(Context context, ArrayList<Student> student) {
this.context = context;
this.student = student;
}
#NonNull
#Override
public AttendanceViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.template_card_student, parent, false);
return new AttendanceViewHolder(view);
}
public void selectAll() {
isSelectedAll = true;
notifyDataSetChanged();
}
public void unSelectAll() {
isSelectedAll = false;
notifyDataSetChanged();
}
public Boolean checkElementExist(String element) {
return plist.contains(element);
}
public void selectLeftOver(int nextPosition) {
for (int i = nextPosition; nextPosition > getItemCount(); i++) {
if (!checkElementExist(student.get(i).getStudentID())) {
plist.add(student.get(i).getStudentID());
}
}
}
#Override
public void onBindViewHolder(#NonNull AttendanceViewHolder holder, int position) {
final Student selectedList = student.get(position);
holder.cbAttendance.setSelected(selectedList.getSelected());
holder.cbAttendance.setTag(position);
if (isSelectedAll) {
selectedList.setSelected(true);
if (!checkElementExist(student.get(position).getStudentID())) {
plist.add(student.get(position).getStudentID());
selectLeftOver(position + 1);
}
} else {
selectedList.setSelected(false);
if (!checkElementExist(student.get(position).getStudentID())) {
plist.remove(student.get(position).getStudentID());
}
}
holder.cbAttendance.setChecked(selectedList.getSelected());
}
#Override
public int getItemCount() {
return student.size();
}
class AttendanceViewHolder extends RecyclerView.ViewHolder {
CardView cvStudentCard;
ImageView imgStudentPicture;
TextView txtStudentName;
CheckBox cbAttendance;
public AttendanceViewHolder(#NonNull View itemView) {
super(itemView);
cvStudentCard = itemView.findViewById(R.id.card_student_view);
imgStudentPicture = itemView.findViewById(R.id.img_student_picture);
txtStudentName = itemView.findViewById(R.id.tv_card_title);
cbAttendance = itemView.findViewById(R.id.cb_attendance);
}
}
}
My application failed to update view after inserting items. I am currently using MVP for building my application. I followed this guide. The author didn't give any further explanations about insert or remove item from list.
I've updated my RecyclerView to latest version (recyclerview-v7:28.0.0). I already checked my layout and also scrolling down. In my latest effort, I know that the list is successfully added, but my getItemCount is not updated yet. I insert inside model and after that notify adapter in Activity (notifyItemInserted). I've tried using notifyDataSetChanged but nothing works.
public class MainActivity extends AppCompatActivity implements MVPInterface.viewActivity{
private RecyclerView.Adapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState){
recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
adapter = new WordAdapter(this);
recyclerView.setAdapter(adapter);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
mPresenter = new ActivityPresenter(this);
addButton = (FloatingActionButton) findViewById(R.id.fab);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mPresenter.onAddList();
}
});
}
#Override
public void AddSuccess(int size){
Log.d("HELLO","createthis "+size);
recyclerView.getAdapter().notifyItemInserted(size);
recyclerView.smoothScrollToPosition(size);
recyclerView.getAdapter().notifyDataSetChanged();
}
}
class WordAdapter extends RecyclerView.Adapter<WordAdapter.WordViewHolder>{
#NonNull
#Override
public WordViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Log.d("CREATE","create");
android.view.View mItemView = mInflater.inflate(R.layout.content_main, viewGroup, false);
return new WordViewHolder(mItemView, this);
}
#Override
public void onBindViewHolder(#NonNull WordViewHolder viewHolder, int position) {
Log.d("CREATE1","bind");
mPresenter.onSetView(viewHolder, position);
}
#Override
public int getItemCount() {
int size = mPresenter.getListSize();
Log.d("item", ""+size);
return mPresenter.getListSize();
}
public class WordViewHolder extends RecyclerView.ViewHolder implements MVPInterface.WordHolder, android.view.View.OnClickListener {
public TextView wordItemView;
final WordAdapter mAdapter;
public WordViewHolder(android.view.View mItemView, WordAdapter wordAdapter) {
super(mItemView);
wordItemView = (TextView) mItemView.findViewById(R.id.word);
this.mAdapter = wordAdapter;
mItemView.setOnClickListener(this);
}
#Override
public void setText(String string) {
wordItemView.setText(string);
}
#Override
public void onClick(android.view.View v) {
wordItemView.setText ("Clicked! "+ wordItemView.getText());
}
}
}
public class AdapterPresenter {
private LinkedList<String> wordList;
private WordModel model;
public AdapterPresenter(){
this.model = new WordModel();
this.wordList = model.initList();
}
public void onSetView(MVPInterface.WordHolder holder, int position) {
holder.setText(wordList.get(position));
}
public int getListSize(){
return model.getSize();
}
}
public class WordModel {
private LinkedList<String> wordList = new LinkedList<>();
private MVPInterface.viewActivity activity;
private boolean isFirst = true;
//private Listener listener;
public WordModel(){
this.wordList = initList();
}
public LinkedList<String> initList(){
if(isFirst){
for(int i = 0; i<20; i++){
wordList.addLast("Word "+i);
}
isFirst = false;
}
return wordList;
}
public LinkedList<String> getWordList(){
return wordList;
}
public int getSize(){
return wordList.size();
}
public void addList(Listener listener){
wordList.add("+ Word "+ getSize());
listener.onAddSuccess();
}
}
public class ActivityPresenter implements Listener {
private WordModel wordModel;
private MVPInterface.viewActivity activity;
public ActivityPresenter(MVPInterface.viewActivity activity){
this.activity = activity;
this.wordModel = new WordModel();
}
public void onAddList() {
wordModel.addList(this);
}
#Override
public void onAddSuccess() {
int size = wordModel.getSize();
activity.AddSuccess(size);
}
}
The list is successfully inserted (create this logcat message) but getItemCount remains same (CREATEItem).
Android Logcat:
EDIT
I suspect that there's might be problem inside AdapterPresenter. I initialized wordModel inside presenter and thus making my list not dynamically changed (as in logcat, getItemCount won't update to lastest size). But i still don't know what is the exactly problem.
I think you should remove setHasFixedSize(true) or replace it with setHasFixedSize(false)
I made RecyclerView inside RecyclerView. There is ClassCastException at onBindViewHolder.
The error message here.
java.lang.ClassCastException: com.work.hany.playinseoul.main.adapter.MainRecyclerViewAdapter$TourViewHolder$TourSectionItemsAdapter$TourItemViewHolder cannot be cast to com.work.hany.playinseoul.main.adapter.MainRecyclerViewAdapter$CategoryViewHolder$CategoryItemViewHolder
at com.work.hany.playinseoul.main.adapter.MainRecyclerViewAdapter$CategoryViewHolder$CategoryHorizontalAdapter.onBindViewHolder(MainRecyclerViewAdapter.java:216)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6673)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6714)
But I could not catch ClassCastException at TourSectionItemsAdapter onBindViewHolder.
So, I can't check holder type at TourSectionItemsAdapter onBindViewHolder.
Only I caught ClassCastException at MainRecyclerViewAdapter onBindViewHolder.
But MainRecyclerViewAdapter onBindViewHolder holder type is same cast hodler class. Check screen shot.
My code here.
import android.support.annotation.NonNull;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
...
import java.util.ArrayList;
public class MainRecyclerViewAdapter extends BaseSectionRecyclerAdapter {
private MainRecyclerViewAdapter.ItemListener mainItemListener;
private RecyclerView.RecycledViewPool recycledViewPool;
public interface ItemListener {
void onTourClicked(AreaTour tour);
void onMoreTourClicked(AreaTour tour);
}
public MainRecyclerViewAdapter(ArrayList<Section> sections, MainRecyclerViewAdapter.ItemListener mainItemListener) {
this.mainItemListener = mainItemListener;
this.sections = sections;
}
#Override
public void onAttachedToRecyclerView(#NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
this.recycledViewPool = recyclerView.getRecycledViewPool();
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
Section.ItemType currentItemType = getCurrentItemType(viewType);
View itemView;
switch (currentItemType) {
case CATEGORY:
itemView = inflater.inflate(R.layout.main_recycler_row_category, parent, false);
CategoryViewHolder categoryViewHolder = new CategoryViewHolder(itemView);
categoryViewHolder.categoryRecyclerView.setRecycledViewPool(recycledViewPool);
viewHolder = categoryViewHolder;
break;
case MAIN_TOUR:
itemView = inflater.inflate(R.layout.main_recycler_row_tour, parent, false);
TourViewHolder tourViewHolder = new TourViewHolder(itemView);
tourViewHolder.tourSectionItemsRecyclerView.setRecycledViewPool(recycledViewPool);
viewHolder = tourViewHolder;
break;
}
return viewHolder;
}
private int categoryRecyclerViewScrollPosition = 0;
#Override
public void onViewRecycled(#NonNull ViewHolder holder) {
super.onViewRecycled(holder);
if (Section.ItemType.CATEGORY.getCode() == holder.getItemViewType()) {
CategoryViewHolder categoryViewHolder = CategoryViewHolder.class.cast(holder);
RecyclerView categoryRecyclerView = categoryViewHolder.categoryRecyclerView;
categoryRecyclerViewScrollPosition = categoryRecyclerView.computeHorizontalScrollOffset();
}
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
super.onBindViewHolder(holder, position);
try {
if (Section.ItemType.CATEGORY.getCode() == holder.getItemViewType()) {
CategoryViewHolder categoryViewHolder = CategoryViewHolder.class.cast(holder);
categoryViewHolder.categoryRecyclerView.scrollBy(categoryRecyclerViewScrollPosition, 0);
}
} catch (ClassCastException e) {
Log.e("HANY_TAG", "MainRecyclerViewAdapter.onBindViewHolder" + e.getClass().getSimpleName());
// But.... holder type is CategoryViewHolder.
}
}
class TourViewHolder extends ViewHolder<ArrayList<AreaTour>> {
private ImageView tourSectionImageView;
private TextView tourSectionTitleTextView;
private RecyclerView tourSectionItemsRecyclerView;
public TourViewHolder(View itemView) {
super(itemView);
tourSectionImageView = itemView.findViewById(R.id.tour_content_image_view);
tourSectionTitleTextView = itemView.findViewById(R.id.tour_section_title_text_view);
tourSectionItemsRecyclerView = itemView.findViewById(R.id.tour_section_item_recycler_view);
}
#Override
public void bind(final ArrayList<AreaTour> areaTour) {
String sectionTitle = ConverterUtils.convertContentType(areaTour.get(0).getContentTypeId());
tourSectionTitleTextView.setText(sectionTitle);
ImageLoderUtils.lodeURI(tourSectionImageView, areaTour.get(areaTour.size() - 1).getLargeImage());
TourSectionItemsAdapter tourSectionItemsAdapter = new TourSectionItemsAdapter(areaTour);
tourSectionItemsRecyclerView.setLayoutManager(new GridLayoutManager(itemView.getContext(), 2));
tourSectionItemsRecyclerView.setAdapter(tourSectionItemsAdapter);
}
private class TourSectionItemsAdapter extends RecyclerView.Adapter<TourSectionItemsAdapter.TourItemViewHolder> {
private ArrayList<AreaTour> areaTourList;
private final int SECTION_IMAGE_COUNT = 1;
public TourSectionItemsAdapter(ArrayList<AreaTour> areaTourList) {
this.areaTourList = areaTourList;
}
#NonNull
#Override
public TourItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new TourItemViewHolder(inflater.inflate(R.layout.main_recycler_row_tour_item, null));
}
#Override
public void onBindViewHolder(#NonNull TourItemViewHolder holder, int position) {
holder.bind(areaTourList.get(position));
}
#Override
public int getItemCount() {
return areaTourList.size() - SECTION_IMAGE_COUNT;
}
class TourItemViewHolder extends ViewHolder<AreaTour> {
private ImageView tourImageView;
private TextView tourTextView;
private TextView tourAddrTextView;
private TextView tourContentShowCountTextView;
public TourItemViewHolder(View itemView) {
super(itemView);
tourImageView = itemView.findViewById(R.id.tour_content_image_view);
tourTextView = itemView.findViewById(R.id.tour_title_text_view);
tourContentShowCountTextView = itemView.findViewById(R.id.tour_show_text_view);
tourAddrTextView = itemView.findViewById(R.id.tour_content_addr_text_view);
}
public void bind(final AreaTour tour) {
ImageLoderUtils.lodeURI(tourImageView, tour.getLargeImage());
tourTextView.setText(tour.getContentTitle());
String countStr = new StringBuilder().append("์กฐํ์ ").append(tour.getReadCount()).toString();
tourContentShowCountTextView.setText(countStr);
tourAddrTextView.setText(tour.getAreaAddress());
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mainItemListener.onTourClicked(tour);
}
});
}
}
}
}
class CategoryViewHolder extends ViewHolder<ArrayList<ContentType>> {
private RecyclerView categoryRecyclerView;
// private TextView categoryTitleView;
public CategoryViewHolder(View itemView) {
super(itemView);
// categoryTitleView = itemView.findViewById(R.id.main_tour_title_text_view);
categoryRecyclerView = itemView.findViewById(R.id.main_tour_recycler_view);
categoryRecyclerView.setHasFixedSize(true);
}
#Override
public void bind(ArrayList<ContentType> data) {
CategoryHorizontalAdapter categoryHorizontalAdapter = new CategoryHorizontalAdapter(data);
LinearLayoutManager layoutManager = new LinearLayoutManager(itemView.getContext(), LinearLayoutManager.HORIZONTAL, false);
categoryRecyclerView.setLayoutManager(layoutManager);
categoryRecyclerView.setAdapter(categoryHorizontalAdapter);
}
private class CategoryHorizontalAdapter extends RecyclerView.Adapter<CategoryItemViewHolder> {
private ArrayList<ContentType> categoryTypes;
public CategoryHorizontalAdapter(ArrayList<ContentType> categoryTypes) {
this.categoryTypes = categoryTypes;
}
#NonNull
#Override
public CategoryItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return new CategoryItemViewHolder(inflater.inflate(R.layout.main_recycler_row_category_item, null));
}
#Override
public void onBindViewHolder(#NonNull CategoryItemViewHolder holder, int position) {
holder.bind(categoryTypes.get(position));
}
#Override
public int getItemCount() {
return categoryTypes.size();
}
}
private class CategoryItemViewHolder extends ViewHolder<ContentType> {
private TextView categoryTitleTextView;
public CategoryItemViewHolder(View itemView) {
super(itemView);
categoryTitleTextView = itemView.findViewById(R.id.category_item_title_text_view);
}
public void bind(ContentType type) {
categoryTitleTextView.setText(type.getName());
}
}
}
}
BaseSectionRecyclerAdapter code.
abstract public class BaseSectionRecyclerAdapter extends RecyclerView.Adapter<ViewHolder> {
protected ArrayList<Section> sections;
#Override
public int getItemCount() {
return sections.size();
}
public <T>void addSection(Section.ItemType type, T data){
sections.add(new Section(type,data));
notifyDataSetChanged();
}
public <T>void updateSection(Section.ItemType type, T data) {
for(int position = 0, end = sections.size(); position < end; position++ ){
if (sections.get(position).getType().equals(type)) {
sections.get(position).setData(data);
notifyItemChanged(position);
}
}
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.bind((sections.get(position).getData()));
}
#Override
public int getItemViewType(int position) {
return sections.get(position).getType().getCode();
}
protected Section.ItemType getCurrentItemType(int position) {
for (Section.ItemType itemType : Section.ItemType.values()) {
if (itemType.getCode() == position) return itemType;
}
return NOTHING;
}
}
ViewHolder code.
public abstract class ViewHolder<T> extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
abstract public void bind(T data);
}
I don't understand what I did wrong...
How to solve it?
I just faced that issue that I commented above. I was using the switch case in onBindViewHolderfunction and I haven't written the default case, When I added the default case then the error is fixed.
In your case, you are using an if condition in onBindViewHolder(), just try to add an else to the function and try.
hope you fixed the issue if it is not, then try this one. Thank you.
maybe its late but for the feature readers just define viewPool like this
private val viewPool = RecyclerView.RecycledViewPool()