More than one view in recyclerview - android

I read How to create RecyclerView with multiple view type? but didn't understand few things.
First of all, my goal is:
I don't understand how getItemViewType (works in my case):
public int getItemViewType(int position) {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return position % 2 * 2;
}
Because, I want to
set Item2 ONLY after the click not right at the beginning. This causes problems for me to understand, how to implement getItemViewType. Any pseudo code/prototype are more than welcome.
CODE: [FIRST APPROACH - Setting every second row as detail layout and try to hide it on default. Change visibility onClick method later on..]
public class DifferentRowAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Model> items;
FragmentActivity c;
public DifferentRowAdapter(List<Model> items, FragmentActivity c) {
this.items = items;
this.c = c;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case MEAL_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rec_item, parent, false);
return new ViewHolder1(view);
case DETAIL_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.detail_test, parent, false);
return new ViewHolder2(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final Model object = items.get(position);
final int currentPosition = position;
if (object != null) {
switch (object.getmType()) {
case MEAL_TYPE:
((ViewHolder1) holder).mNameTextView.setText(object.getName());
((ViewHolder1) holder).img.setImageResource(R.mipmap.ic_launcher);
break;
case DETAIL_TYPE:
((ViewHolder2) holder).detailsText.setText(object.getDescription());
break;
}
}
}
#Override
public int getItemCount() {
if (items == null)
return 0;
return items.size();
}
#Override
public int getItemViewType(int position) {
// I need ITEM2 to be at third/sixth/nineth ect. position
if(position % 3 == 0){
return DETAIL_TYPE;
}
else{
return MEAL_TYPE;
}
}
public class ViewHolder1 extends RecyclerView.ViewHolder {
TextView mNameTextView;
ImageView img;
mealsItemClickListener icl;
public ViewHolder1(View itemView) {
super(itemView);
mNameTextView = (TextView) itemView.findViewById(R.id.name);
img = (ImageView) itemView.findViewById(R.id.category_image);
}
public TextView getmNameTextView() {
return mNameTextView;
}
public void setmNameTextView(TextView mNameTextView) {
this.mNameTextView = mNameTextView;
}
public ImageView getImg() {
return img;
}
public void setImg(ImageView img) {
this.img = img;
}
}
public class ViewHolder2 extends RecyclerView.ViewHolder {
TextView detailsText;
mealsItemClickListener icl;
public ViewHolder2(View v) {
super(v);
detailsText = (TextView) itemView.findViewById(R.id.desc);
}
public TextView getDetailsText() {
return detailsText;
}
public void setDetailsText(TextView detailsText) {
this.detailsText = detailsText;
}
}
}
[2 APPROACH - Try to add ITEM2 onClick]
public class DifferentRowAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Model> items;
FragmentActivity c;
public DifferentRowAdapter(List<Model> items, FragmentActivity c) {
this.items = items;
this.c = c;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case MEAL_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rec_item, parent, false);
return new ViewHolder1(view);
case DETAIL_TYPE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.detail_test, parent, false);
return new ViewHolder2(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final Model object = items.get(position);
final int currentPosition = position;
if (object != null) {
switch (object.getmType()) {
case MEAL_TYPE:
((ViewHolder1) holder).mNameTextView.setText(object.getName());
((ViewHolder1) holder).img.setImageResource(R.mipmap.ic_launcher);
break;
case DETAIL_TYPE:
((ViewHolder2) holder).detailsText.setText(object.getDescription());
break;
}
//THIS METHOD WORKS FINE POSITIONING WISE, BUT IT DUPLICATES CLICKED ITEM INSTEAD OF PUTTING ITEM2
((ViewHolder1) holder).img.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
Toast.makeText(c, "Position: " + currentPosition, Toast.LENGTH_SHORT).show();
addItem(currentPosition, object);
}
});
}
}
#Override
public int getItemCount() {
if (items == null)
return 0;
return items.size();
}
#Override
public int getItemViewType(int position) {
if (items != null) {
Model object = items.get(position);
if (object != null) {
return object.getmType();
}
}
return 0;
}
// Check if clicked item is left/right
private boolean isLeft(final int position){
if (position % 2 == 0){
return true; // Returns 1 if it's left columns item
}
else return false;
}
// Add item at wanted position. If left pos+2, if right+1.
private void addItem(final int position, Model object){
if(isLeft(position)){
items.add(position+2, object);
notifyItemInserted(position+2);
}
else{
items.add(position+1, object);
notifyItemInserted(position+1);
}
}
public class ViewHolder1 extends RecyclerView.ViewHolder {
TextView mNameTextView;
ImageView img;
mealsItemClickListener icl;
public ViewHolder1(View itemView) {
super(itemView);
mNameTextView = (TextView) itemView.findViewById(R.id.name);
img = (ImageView) itemView.findViewById(R.id.category_image);
}
public TextView getmNameTextView() {
return mNameTextView;
}
public void setmNameTextView(TextView mNameTextView) {
this.mNameTextView = mNameTextView;
}
public ImageView getImg() {
return img;
}
public void setImg(ImageView img) {
this.img = img;
}
}
public class ViewHolder2 extends RecyclerView.ViewHolder {
TextView detailsText;
mealsItemClickListener icl;
public ViewHolder2(View v) {
super(v);
detailsText = (TextView) itemView.findViewById(R.id.desc);
}
public TextView getDetailsText() {
return detailsText;
}
public void setDetailsText(TextView detailsText) {
this.detailsText = detailsText;
}
}
}
TL;DR ON MY SITUATION:
Approach1: Gives me
java.lang.ClassCastException: com.example.mrti.menuapp.MULTI.DifferentRowAdapter$ViewHolder2 cannot be cast to com.example.mrti.menuapp.MULTI.DifferentRowAdapter$ViewHolder1
at com.example.mrti.menuapp.MULTI.DifferentRowAdapter.onBindViewHolder(DifferentRowAdapter.java:62)
Approach2: Adding item at certain position works fine, but it adds clicked item, not item2. I'd like to focus more on approach2, but if someone can explain first one - I'm okay with that as well. I'm not sure why it is not working, because it should be - or did I miss smth?
PROBABLY APPROACH1 SOLUTION:
In First approach,
with the same position value, the value which getItemViewType(position) returns would not same to the value which items.get(position).getmType() returns.
I have to make values of type same in both getItemViewType and onBindViewHolder method;
How to do it tho?

Related

Have 20 views to inflate plus a footer view in recycler view in Android, but recycler view is inflating 19 views plus the footer view

The ArrayList contains 20 items and I want to show contents from arraylist to the recycler view with 20 views plus I want to add a footer view. But I am getting 19 views and the footer. Here is the code of the Adapter class of Recycler View. If I am increasing size of getItemCount, I am getting indexoutofBound Exception in BindViewHolder Method. Please resolve.
Result movie;
UrlConstants urlConstants = UrlConstants.getSingletonRef();
private ArrayList<Result> moviesList = new ArrayList<>();
private Context context;
private final int VIEW_ITEM = 0;
private final int VIEW_PROG = 1;
Fragment fragment;
public MoviesAdapter(ArrayList<Result> moviesList,Fragment fragment) {
this.moviesList = moviesList;
this.fragment = fragment;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public ImageView backdrop_image;
public TextView title, date;
public MyViewHolder(View view) {
super(view);
backdrop_image = (ImageView)view.findViewById(R.id.backdrop_image);
title = (TextView) view.findViewById(R.id.title);
date = (TextView) view.findViewById(R.id.date);
}
}
public class FooterViewHolder extends RecyclerView.ViewHolder
{
public TextView tag_text,previous_page,next_page,between_text;
public FooterViewHolder(View itemView) {
super(itemView);
between_text = (TextView) itemView.findViewById(R.id.between_text);
tag_text = (TextView)itemView.findViewById(R.id.tag_text);
previous_page = (TextView)itemView.findViewById(R.id.previous_page);
next_page = (TextView) itemView.findViewById(R.id.next_page);
}
}
#Override
public int getItemViewType(int position) {
if (isPositionItem(position))
return VIEW_ITEM;
return VIEW_PROG;
}
private boolean isPositionItem(int position) {
return position != getItemCount() -1;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
if (viewType == VIEW_ITEM) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.movie_list_row, parent, false);
return new MyViewHolder(v);
} else if (viewType == VIEW_PROG){
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.footer_layout, parent, false);
return new FooterViewHolder(v);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof MyViewHolder)
{
movie = moviesList.get(position);
((MyViewHolder)holder).title.setText(movie.getTitle());
((MyViewHolder)holder).date.setText(movie.getReleaseDate());
String url = urlConstants.URL_Image + movie.getBackdropPath();
Picasso.with(context)
.load(url)
.into(((MyViewHolder)holder).backdrop_image);
}
else if (holder instanceof FooterViewHolder)
{
movie = moviesList.get(position);
((FooterViewHolder)holder).tag_text.setText("Viewing " + movie.getPage() + " of " + movie.getTotal_pages() + " Pages" );
((FooterViewHolder)holder).previous_page.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
((MoviesMainFragment)fragment).prepareOnlineData(movie.getPage() - 1);
}
});
((FooterViewHolder)holder).next_page.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MoviesMainFragment)fragment).prepareOnlineData(movie.getPage() + 1);
}
});
}
}
#Override
public int getItemCount()
{
return this.moviesList.size();
}
You have to increase the movilist size by 1. To do that, you have to insert a dummy data into the last item of the list so that the last item doesn't have null data and you don't get Indexoutofbound.
No need to increase size getItemCount, you have already added dummy item in the list so.
Problem
this line
return position != getItemCount() -1;
You have 20 items, i.e. item0..item19. The above will check for only 19 items, i.e. upto item18. When the recycler view reaches the last position, based on the condition it will inflate the footer view and thus ignores the last item.
Solution
Below code works for me.
Change your isPositionItem() method like below
private boolean isPositionItem(int position) {
return position == moviesList.size();
}
Change your getItemCount() like below
#Override
public int getItemCount()
{
return this.moviesList.size()+1;
}

Single selected item on recyclerview android

I'm trying to highlight onmy one item on my recyclerview when user click. But I have an unexpected behavior.
When I click on one item, the adapter logs me that that one is selected and hightlighted. But when I scroll, I see that there are other items highlighted.
Any help on that issue will be really appreciate.
My codes:
My Adapter
public class ChooseRecipientAdapter extends RecyclerView.Adapter<ChooseRecipientViewHolder> {
#Override
public ChooseRecipientViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_recipients_item, null);
ChooseRecipientViewHolder cv = new ChooseRecipientViewHolder(this.context, v);
return cv;
}
#Override
public void onBindViewHolder(final ChooseRecipientViewHolder holder, final int position) {
RecipientItem settingsRecipients = recipientItems.get(position);
settingsRecipients.holder = holder;
holder.title.setText(settingsRecipients.title);
holder.recipient = recipients.get(position);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (selectedItem < 0) {
selectedItem = position;
holder.isSelected = true;
holder.itemView.setSelected(true);
holder.title.setTextColor(context.getResources().getColor(R.color.color_background));
} else if (holder.isSelected) {
selectedItem = -1;
holder.isSelected = false;
holder.itemView.setSelected(false);
holder.title.setTextColor(context.getResources().getColor(R.color.textColorPrimary));
ChooseRecipientActivity.recipient = null;
} else {
if (getItem(selectedItem).holder != null) {
getItem(selectedItem).holder.isSelected = false;
getItem(selectedItem).holder.itemView.setSelected(false);
getItem(selectedItem).holder.title.setTextColor(context.getResources().getColor(R.color.textColorPrimary));
selectedItem = position;
holder.isSelected = true;
holder.itemView.setSelected(true);
holder.title.setTextColor(context.getResources().getColor(R.color.color_background));
ChooseRecipientActivity.recipient = holder.recipient;
}
}
}
});
}
My ViewHolder
public class ChooseRecipientViewHolder extends RecyclerView.ViewHolder {
public String id;
public Context context;
public ImageView leftImageView;
public TextView title;
public boolean isSelected = false;
public Recipient recipient;
public View itemView;
public ChooseRecipientViewHolder(final Context context, View view) {
super(view);
this.context = context;
this.leftImageView = (ImageView) view.findViewById(R.id.leftIcon);
this.title = (TextView) view.findViewById(R.id.title);
itemView = view;
}
}
A screenshot:
Highligted issue
The issue is that you need to reset your ViewHolder selected status if the row isn't selected.
if(selected) {
setRowColour();
} else {
resetColourToDefaults();
}
This is extremely important, because RecyclerView will reuse ViewHolder rows as you scroll up and down. A reused row will retain the formatting that was applied to it previously.

Android cards multiple layouts based on position

I want to use different layouts based on card position on screen. For example I need that first card (position 0 uses layout first_card.xml) and other cards should use other_cards.xml layout and it should be positioned horizontally (see picture below (picture taken from official google site)).
Here's my code
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder>{
private List<CardData> mItems;
private Context context;
private SendInfoToCards cardDatas;
private boolean mainMenu;
private static final int FIRST = 1;
private static final int SECOND = 2;
public CardAdapter(Context c, SendInfoToCards datas, boolean main) {
super();
this.context = c;
this.cardDatas = datas;
mItems = datas.getList();
this.mainMenu = main;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
if(!mainMenu) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_card_item, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(v);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView city = (TextView) v.findViewById(R.id.tv_movie);
String fragmentSwitcher = city.getText().toString();
if (fragmentSwitcher.equals("Zemelapis")) {
switchFragments(0);
} else {
switchFragments(1);
}
}
});
return viewHolder;
} else {
View v;
if(position == 0){
v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
}else{
v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
}
ViewHolder viewHolder = new ViewHolder(v);
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView city = (TextView) v.findViewById(R.id.tv_movie);
String fragmentSwitcher = city.getText().toString();
}
});
return viewHolder;
}
}
private void switchFragments(int nr){
if(nr == 0){
Log.d("TAG", "mapo");
} else {
Intent intent = new Intent(context, DetailTourActivity.class);
context.startActivity(intent);
}
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
if(i != 0){
} else {
CardData data = mItems.get(i);
viewHolder.tvMovie.setText(data.getName());
viewHolder.imgThumbnail.setImageResource(data.getThumbnail());
}
}
#Override
public int getItemCount() {
return mItems.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public ImageView imgThumbnail;
public TextView tvMovie;
public ViewHolder(View itemView) {
super(itemView);
imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail);
tvMovie = (TextView)itemView.findViewById(R.id.tv_movie);
}
}
}
Sadly but onCreateViewHolder method second argument position is always 0. Why is that? How to fix it?
Here is what your adapter class should roughly look like
public class CardAdapter extends RecyclerView.Adapter<RecylerView.ViewHolder>{
private List<CardData> mItems;
private Context context;
private SendInfoToCards cardDatas;
private boolean mainMenu;
private static final int FIRST = 1;
private static final int SECOND = 2;
public CardAdapter(Context c, SendInfoToCards datas, boolean main) {
super();
this.context = c;
this.cardDatas = datas;
mItems = datas.getList();
this.mainMenu = main;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
if(type == SECOND){
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
return new SecondViewViewHolder(v);
} else {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
return new FirstViewViewHolder(v);
}
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
if(viewHolder instanceof SecondViewViewHolder){
SecondViewViewHolder secondViewViewHolder = (SecondViewViewHolder) viewHolder;
// bind second views
secondViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
} else {
FirstViewViewHolder firstViewViewHolder = (FirstViewViewHolder) viewHolder;
// bind firs view
firstViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
}
}
#Override
public int getItemViewType(int position) {
if (position == 0) {
return FIRST;
} else {
return SECOND;
}
}
#Override
public int getItemCount() {
return mItems.size();
}
class FirstViewViewHolder extends RecyclerView.ViewHolder{
public ImageView imgThumbnail;
public TextView tvMovie;
public FirstViewViewHolder(View itemView) {
super(itemView);
imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail);
tvMovie = (TextView)itemView.findViewById(R.id.tv_movie);
}
}
class SecondViewViewHolder extends RecyclerView.ViewHolder{
public ImageView imgThumbnail;
public TextView tvMovie;
public ImageView imgThumbnail2;
public TextView tvMovie2;
public SecondViewViewHolder(View itemView) {
super(itemView);
//find viewby id
}
}
}
What is changed
Since recyclerview can handle multiple view types you can decide which layout to inflate depending on some condition. You do this by overriding getItemViewTypeMethod() of the RecylerView Adapter
#Override
public int getItemViewType(int position) {
if (position == 0) {
return FIRST;
} else {
return SECOND;
}
}
When creating viewholder. the onCreateViewHolder method will get the view type. Based on the type you should inflate the appropriate layout and return the appropriate viewholder
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int type) {
if(type == SECOND){
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.second_layout, viewGroup, false);
return new SecondViewViewHolder(v);
} else {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.first_layout, viewGroup, false);
return new FirstViewViewHolder(v);
}
}
Since there are two layouts involved, I have created two View Holders to hold first and second layouts. (FirstViewHolder & SecondViewHolder). Because of this you have to set your adapter's ViewHolder type to the base ViewHolder class like this
public class CardAdapter extends RecyclerView.Adapter<RecylerView.ViewHolder>{
...
}
and now in the onBindViewHolder method, you can determine which ViewHolder is currently being bound and do your work accordingly
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
if(viewHolder instanceof SecondViewViewHolder){
SecondViewViewHolder secondViewViewHolder = (SecondViewViewHolder) viewHolder;
// bind second views
secondViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
} else {
FirstViewViewHolder firstViewViewHolder = (FirstViewViewHolder) viewHolder;
// bind firs view
firstViewViewHolder.imgThumbnail.setImageResource(R.id.img_resource);
}
}
Check this for an example
The thing is that the second parameter is not position, it is viewType.
From the docs:
public abstract VH onCreateViewHolder (ViewGroup parent, int viewType)
Look at public void onBindViewHolder (VH holder, int position, List<Object> payloads), this is what you actually need

Implementing RecyclerView with Sectioned Header based on Category

I am trying to implement RecyclerView with custom sectioned header based on list's category. I already have a list that's sorted based on their category, so I want to inflate header if and only if one row's category is different from preceding row's category. I've been figuring out how to do it but something bothering me here. It worked, but does not display the right row. I think it's because of the item count which is increased due to the header. Can anyone help me?
Here is my adapter :
List<Notes> notes;
OnItemClickListener mItemClickListener;
private static final int TYPE_CATEGOORY = 0;
private static final int TYPE_ITEM = 1;
String changing = "";
public OneNoteAdapter(List<Notes> logs) {
this.notes = logs;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == TYPE_CATEGOORY){
View itemView = LayoutInflater.
from(parent.getContext()).
inflate(R.layout.category_header, parent, false);
return new HeaderViewHolder(itemView);
}else{
View itemView = LayoutInflater.
from(parent.getContext()).
inflate(R.layout.learn_card, parent, false);
return new ItemViewHolder(itemView);
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if(holder instanceof HeaderViewHolder){
Notes note = notes.get(position);
((HeaderViewHolder) holder).vCategoryText.setText(note.category);
}else {
ItemViewHolder item = (ItemViewHolder) holder;
Notes note = notes.get(position);
item.vNotesNote.setText(note.notes);
item.vNotesCat.setText(note.category);
}
}
#Override
public int getItemViewType(int position) {
if((!(notes.get(position).category).equals(changing))){
changing = notes.get(position).category;
return TYPE_CATEGOORY;
}else{
return TYPE_ITEM;
}
}
#Override
public int getItemCount() {
return notes.size();
}
public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
protected TextView vNotesNote, vNotesCat;
private final Context context;
public ItemViewHolder(View itemView) {
super(itemView);
vNotesNote = (TextView) itemView.findViewById(R.id.notes_notes);
vNotesCat = (TextView) itemView.findViewById(R.id.notes_category);
context = itemView.getContext();
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(mItemClickListener != null){
mItemClickListener.onItemClick(v, getPosition());
}
}
}
public class HeaderViewHolder extends RecyclerView.ViewHolder {
protected TextView vCategoryText;
public HeaderViewHolder(View itemView) {
super(itemView);
vCategoryText = (TextView) itemView.findViewById(R.id.category_header_text);
}
}
public interface OnItemClickListener{
public void onItemClick(View v, int poition);
}
public void setOnItemClickListener (final OnItemClickListener mItemClickListener){
this.mItemClickListener = mItemClickListener;
}
}
Thank You
Try to replace your onBindViewHolder and getItemViewType methods with following:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof HeaderViewHolder) {
((HeaderViewHolder) holder).vCategoryText.setText(notes.get(position + 1).category);
} else {
ItemViewHolder item = (ItemViewHolder) holder;
Notes note = notes.get(position);
item.vNotesNote.setText(note.notes);
item.vNotesCat.setText(note.category);
if (position + 1 < notes.size() &&
!notes.get(position + 1).category.equals(note.category)) {
notes.add(position + 1, null);
}
}
}
#Override
public int getItemViewType(int position) {
if (notes.get(position) == null) {
return TYPE_CATEGOORY;
} else {
return TYPE_ITEM;
}
}
And you can delete String changing = "";.

views lost on scrolling recylerview

I am populating a dynamic list in my recyclerView
which looks like this, now if you notice there is a '+' icon which on clicking
generates a view which is hidden initially which looks like this
the problem I am facing is whenever I open more than 2-3 items and scroll, unexpectedly other items are closed and data inside them is also erased, I have tried maintaining a flag "isExpanded" to keep a check on items expanded but it doesn't seem to work with the first and last items (i.e if I open the 1st item and scroll down to the last item and open it the 1st is closed and vice versa)
I am open to completely different solution to my approach or even relevant solutions would do.
Here is my Adapter class
public class Step9LaborAdapter extends RecyclerView.Adapter<Step9LaborAdapter.ChildViewHolder> implements View.OnFocusChangeListener {
List<Step9_DB.Labor> laborList;
public EditText chkFOcus;
public Step9LaborAdapter(List<Step9_DB.Labor> mlaborList) {
this.laborList = mlaborList;
}
public List<Step9_DB.Labor> getAllItems() {
return laborList;
}
#Override
public ChildViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_step10labor, parent, false);
ChildViewHolder vh = new ChildViewHolder(view);
return vh;
}
#Override
public void onBindViewHolder(ChildViewHolder holder, int position) {
final Step9_DB.Labor laborItem = getItem(position);
holder.tv_laborTitle.setText(laborItem.getLaborName());
holder.s.setText(laborItem.getS());
holder.m.setText(laborItem.getM());
holder.m_plus.setText(laborItem.getM_plus());
holder.l.setText(laborItem.getL());
holder.s.setOnFocusChangeListener(this);
holder.s.setTag(position);
holder.m.setOnFocusChangeListener(this);
holder.m.setTag(position);
holder.m_plus.setOnFocusChangeListener(this);
holder.m_plus.setTag(position);
holder.l.setOnFocusChangeListener(this);
holder.l.setTag(position);
holder.tv_show_option.setTag(R.string.laboritem, holder);
holder.tv_show_option.setTag(laborItem);
holder.tv_show_option.setTag(R.string.labor_pos, position);
holder.tv_show_option.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ChildViewHolder childViewHolder = (ChildViewHolder) view.getTag(R.string.laboritem);
int pos = (int) view.getTag(R.string.labor_pos);
Step9_DB.Labor labor = (Step9_DB.Labor) view.getTag();
if (labor.isExpanded()) {
childViewHolder.ll_options.setVisibility(View.GONE);
getItem(pos).setIsExpanded(false);
} else {
childViewHolder.ll_options.setVisibility(View.VISIBLE);
getItem(pos).setIsExpanded(true);
}
notifyDataSetChanged();
}
});
}
private Step9_DB.Labor getItem(int position) {
return laborList.get(position);
}
#Override
public int getItemCount() {
if (laborList != null)
return laborList.size();
else return 0;
}
public void setChkFOcus(EditText chkFOcus) {
this.chkFOcus = chkFOcus;
}
public EditText getChkFOcus() {
return chkFOcus;
}
public class ChildViewHolder extends RecyclerView.ViewHolder {
public TextView tv_laborTitle, tv_show_option;
public EditText s, m_plus, m, l;
LinearLayout ll_options;
public ChildViewHolder(View itemView) {
super(itemView);
tv_laborTitle = (TextView) itemView.findViewById(R.id.tv_labor_type);
tv_show_option = (TextView) itemView.findViewById(R.id.tv_show_option);
ll_options = (LinearLayout) itemView.findViewById(R.id.ll_working_days);
s = (EditText) itemView.findViewById(R.id.et_s);
m = (EditText) itemView.findViewById(R.id.et_m);
m_plus = (EditText) itemView.findViewById(R.id.et_m_plus);
l = (EditText) itemView.findViewById(R.id.et_l);
}
}
}
Please ask me if other class code is also required because I think adapter class is enough.
You have to manage your states inside onscroll method. Please do coding according to your need inside onscoll. Insert following code on your mainactivity or fragment where your recyclerView is created.
recylerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = layoutmanager.getChildCount();
ViewHolder holder=new ViewHolder();
for (int m=0;m<visibleItemCount;m++){
holder.view= recyclerView.getChildAt(m);
int position=recyclerView.getChildAdapterPosition(holder.view);
//============initialize your all viewitems like this to avoid null pointer //exception
holder.tv_show_option=(TextView)holder.view.findViewById(R.id.tv_show_option);
holder.tv_show_option.setText(yourdataitemlikearraylist.get(positionitem));
final Step9_DB.Labor laborItem = getItem(position);
holder.tv_laborTitle.setText(laborItem.getLaborName());
holder.s.setText(laborItem.getS());
holder.m.setText(laborItem.getM());
holder.m_plus.setText(laborItem.getM_plus());
holder.l.setText(laborItem.getL());
holder.s.setOnFocusChangeListener(this);
holder.s.setTag(position);
holder.m.setOnFocusChangeListener(this);
holder.m.setTag(position);
holder.m_plus.setOnFocusChangeListener(this);
holder.m_plus.setTag(position);
holder.l.setOnFocusChangeListener(this);
holder.l.setTag(position);
holder.tv_show_option.setTag(R.string.laboritem, holder);
holder.tv_show_option.setTag(laborItem);
holder.tv_show_option.setTag(R.string.labor_pos, position);
holder.tv_show_option.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ChildViewHolder childViewHolder = (ChildViewHolder) view.getTag(R.string.laboritem);
int pos = (int) view.getTag(R.string.labor_pos);
Step9_DB.Labor labor = (Step9_DB.Labor) view.getTag();
if (labor.isExpanded()) {
childViewHolder.ll_options.setVisibility(View.GONE);
getItem(pos).setIsExpanded(false);
} else {
childViewHolder.ll_options.setVisibility(View.VISIBLE);
getItem(pos).setIsExpanded(true);
}
notifyDataSetChanged();
}
});
}
}
});
//======add innerclass viewholder
private static class ViewHolder{
View view ;
public TextView tv_laborTitle, tv_show_option;
public EditText s, m_plus, m, l;
LinearLayout ll_options;
}
Thank you for your answer but i solved it by rectifying my mistake for not checking isExpanded conditions on bindViewHolder on the first place.
public class Step9LaborAdapter extends RecyclerView.Adapter<Step9LaborAdapter.ChildViewHolder> implements View.OnFocusChangeListener {
List<Step9_DB.Labor> laborList;
public EditText chkFOcus;
public Step9LaborAdapter(List<Step9_DB.Labor> mlaborList) {
this.laborList = mlaborList;
}
public List<Step9_DB.Labor> getAllItems() {
return laborList;
}
#Override
public ChildViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_step10labor, parent, false);
ChildViewHolder vh = new ChildViewHolder(view);
return vh;
}
#Override
public void onBindViewHolder(ChildViewHolder holder, int position) {
final Step9_DB.Labor laborItem = getItem(position);
holder.tv_laborTitle.setText(laborItem.getLaborName());
holder.s.setText(laborItem.getS());
holder.m.setText(laborItem.getM());
holder.m_plus.setText(laborItem.getM_plus());
holder.l.setText(laborItem.getL());
holder.s.setOnFocusChangeListener(this);
holder.s.setTag(position);
holder.m.setOnFocusChangeListener(this);
holder.m.setTag(position);
holder.m_plus.setOnFocusChangeListener(this);
holder.m_plus.setTag(position);
holder.l.setOnFocusChangeListener(this);
holder.l.setTag(position);
holder.tv_show_option.setTag(R.string.laboritem, holder);
holder.tv_show_option.setTag(laborItem);
holder.tv_show_option.setTag(R.string.labor_pos, position);
Step9_DB.Labor labor = (Step9_DB.Labor) view.getTag();
if (labor.isExpanded()) {
holder.ll_options.setVisibility(View.GONE);
getItem(pos).setIsExpanded(false);
} else {
holder.ll_options.setVisibility(View.VISIBLE);
getItem(pos).setIsExpanded(true);
}
holder.tv_show_option.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ChildViewHolder childViewHolder = (ChildViewHolder) view.getTag(R.string.laboritem);
int pos = (int) view.getTag(R.string.labor_pos);
Step9_DB.Labor labor = (Step9_DB.Labor) view.getTag();
if (labor.isExpanded()) {
childViewHolder.ll_options.setVisibility(View.GONE);
getItem(pos).setIsExpanded(false);
} else {
childViewHolder.ll_options.setVisibility(View.VISIBLE);
getItem(pos).setIsExpanded(true);
}
notifyDataSetChanged();
}
});
}
private Step9_DB.Labor getItem(int position) {
return laborList.get(position);
}
#Override
public int getItemCount() {
if (laborList != null)
return laborList.size();
else return 0;
}
public void setChkFOcus(EditText chkFOcus) {
this.chkFOcus = chkFOcus;
}
public EditText getChkFOcus() {
return chkFOcus;
}
public class ChildViewHolder extends RecyclerView.ViewHolder {
public TextView tv_laborTitle, tv_show_option;
public EditText s, m_plus, m, l;
LinearLayout ll_options;
public ChildViewHolder(View itemView) {
super(itemView);
tv_laborTitle = (TextView) itemView.findViewById(R.id.tv_labor_type);
tv_show_option = (TextView) itemView.findViewById(R.id.tv_show_option);
ll_options = (LinearLayout) itemView.findViewById(R.id.ll_working_days);
s = (EditText) itemView.findViewById(R.id.et_s);
m = (EditText) itemView.findViewById(R.id.et_m);
m_plus = (EditText) itemView.findViewById(R.id.et_m_plus);
l = (EditText) itemView.findViewById(R.id.et_l);
}
}
}`

Categories

Resources