RecyclerView with one static card and other dynamic cards - android

I need to do this: a RecycleView with CardView. The first card is static: it show "Details for this order". The other cards after the first are dynamics. So I decided to do this code:
public class DocumentTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
private List<DocumentType> document; //lista di card da riempire
private Context context;
public DocumentTypeAdapter(List<DocumentType>document, Context context)
{
this.document = document;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view;
if(viewType == 0)
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_info, parent, false);
ViewSimple simpleView = new ViewSimple(view);
return simpleView;
}
else
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_info, parent, false);
DocumentTypeViewHolder documentTypeViewHolder = new DocumentTypeViewHolder(view);
return documentTypeViewHolder;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
DocumentType documents = document.get(position);
if(getItemViewType(position)!=0)
{
holder.title.setText(documents.getTitle());
holder.cert.setText(documents.getTypeofCertificate());
holder.lastmod.setText(documents.getLastModified());
}
}
#Override
public int getItemCount()
{
return document.size();
}
#Override
public int getItemViewType(int position)
{
return document.size();
}
private class ViewSimple extends RecyclerView.ViewHolder
{
public ViewSimple(View itemView)
{
super(itemView);
}
}
public class DocumentTypeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
TextView title, lastmod,cert;
public DocumentTypeViewHolder(View itemView)
{
super(itemView);
title = (TextView)itemView.findViewById(R.id.tipo);
lastmod = (TextView)itemView.findViewById(R.id.ultimamodifica);
cert = (TextView)itemView.findViewById(R.id.certificato);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
}
}
}
but it doesn't work.
My question are:
how to make the first card static and other dynamics?
my data are in document list. So how to say to method getItemViewType() that the first card is static and others are generated from the size of the list document?
Edit: this is the code with changes:
public class DocumentTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
private static final int STATIC_CARD = 0;
private static final int DYNAMIC_CARD = 1;
private List<DocumentType> document;
private Context context;
public DocumentTypeAdapter(List<DocumentType>document, Context context)
{
this.document = document;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view;
if(viewType == STATIC_CARD)
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_info, parent, false);
ViewSimple simpleView = new ViewSimple(view);
return simpleView;
}
else
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.document_card_type, parent, false);
DocumentTypeViewHolder documentTypeViewHolder = new DocumentTypeViewHolder(view);
return documentTypeViewHolder;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
DocumentType documents = document.get(position);
if(getItemViewType(position)==DYNAMIC_CARD)
{
DocumentTypeViewHolder mHolder = (DocumentTypeViewHolder)holder;
mHolder.data.setText(documents.getData());
mHolder.status.setText(documents.getStatus());
Picasso.with(context).load(documents.getImage().toString()).into(mHolder.image, new com.squareup.picasso.Callback() {
#Override
public void onSuccess() {
Log.d("Picasso","success");
}
#Override
public void onError()
{
Log.d("Picasso","error");
}
});
}
}
#Override
public int getItemCount()
{
return document.size();
}
#Override
public int getItemViewType(int position)
{
if(position == 0)
return STATIC_CARD;
else
return DYNAMIC_CARD;
}
private class ViewSimple extends RecyclerView.ViewHolder
{
public ViewSimple(View itemView)
{
super(itemView);
}
}
public class DocumentTypeViewHolder extends RecyclerView.ViewHolder
{
TextView data, status;
ImageView image;
public DocumentTypeViewHolder(View itemView)
{
super(itemView);
data = (TextView)itemView.findViewById(R.id.dateCharging);
status =(TextView)itemView.findViewById(R.id.statusCharging);
image = (ImageView)itemView.findViewById(R.id.documentImage);
}
}
}
Thanks for your answers

You should override getItemViewType() and make it return a different value when it should be a dynamic card or when its a static card. Since you want the first card to be static you should return a different value when position == 0. This will look something like this:
private static final int STATIC_CARD = 0;
private static final int DYNAMIC_CARD = 1;
#Override
public int getItemViewType(int position) {
if(position == 0) {
return STATIC_CARD;
} else {
return DYNAMIC_CARD;
}
}
Then in your onCreateViewHolder() method you should check the viewType and based on the outcome you should inflate a View, which you were already doing OK, but I would replace the hardcoded 0 with the private static final int STATIC_CARD.
Edit: Just came to my mind, if you only need one static card, you might want to consider placing a CardView in your Fragment/Activity xml layout and place the rest of the dynamic cards in a RecyclerView below that static card.

I'll suggest you to use a library that already correctly implement/handles all that for you: https://github.com/eyeem/RecyclerViewTools
Full disclosure: I wrote the library
Just write your adapter for the dynamic items and then:
DocumentTypeAdapter adapter = new // your adapter here
WrapAdapter wrapAdapter = new WrapAdapter(adapter); // that's from the library
wrapAdapter.addHeader( /* add here your static view */ );
recyclerView.setAdapter(wrapAdapter);
and add those to your build.gradle
repositories {
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
dependencies {
compile 'com.eyeem.recyclerviewtools:library:0.0.3-SNAPSHOT#aar'
}

Related

getItemViewType is not working as supposed

I tried to create a RecycleView for more Objects to display but for some reason funcion getItemViewType doesnt work or it might work but selects second option only because the output from onCreateViewHolder is always the first option.
This is the funcion in the method
private void insertObjects(){
items.add(new Object(1));
items.add(new Object(2));
mMultiAdapter.notifyDataSetChanged();
This is the Adapter
Even if I change first if of getItemViewType to if(position % 2 == 0) > it will output the same option everytime
public class MultiAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public MultiAdapter(List<Object> Parts) { this.items = Parts; }
public static class ChestViewHolder extends RecyclerView.ViewHolder{
TextView second_segment;
private ChestViewHolder( View itemView) {
super(itemView);
second_segment = itemView.findViewById(R.id.segment_tuesday);
}
public static class BackViewHolder extends RecyclerView.ViewHolder {
TextView first_segment;
private BackViewHolder( View itemView) {
super(itemView);
first_segment = itemView.findViewById(R.id.segment_monday);
}
public static class DefaultViewHolder extends RecyclerView.ViewHolder {
TextView default_segment;
private DefaultViewHolder( View itemView) {
super(itemView);
default_segment = itemView.findViewById(R.id.segment_sunday);
}
}
private static int ITEM_TYPE_C_T;
private static int ITEM_TYPE_S_B;
private List<Object> items = new ArrayList<>();
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder Holder, int position) {non code inside of this method}
#Override
public int getItemViewType(int position) {
if (items.get(position).getId()== 1){
return ITEM_TYPE_C_T;
}
else if(items.get(position).getId()== 2){
return ITEM_TYPE_S_B;
}else {
return ITEM_TYPE_C_T;//(DEFAULT)
}
}
#Override
public int getItemCount() {
return items.size();
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == ITEM_TYPE_S_B){
View view = layoutInflater.inflate(R.layout.segment_nOne,parent,false);
return new BackViewHolder(view);
} else if(viewType == ITEM_TYPE_C_T) {
View view = layoutInflater.inflate(R.layout.segment_nTwo,parent,false);
return new ChestViewHolder(view);
}else{
//to prevent crash on null
View view = layoutInflater.inflate(R.layout.nOne,parent,false);
return new DefaultViewHolder(view);
}
}
This is the object
public class Object {
private int id;
public Object(){ }
public Object(int id){
this.id = id;
}
public int getId(){
return id;
}
Thanks for any help

Merging two mostly similar adapters for recyclerview

I have two adapters that adapt to a recycler view depending on different conditions. I want to merge them.
The issue is that I created first in the same file as the activity where it is being used and the other is in a new file.
Take it as follows:
DefaultAdapter is in the file where it is being used.
AutoCompleteAdapter is also used in the same file but is declared in other file.
I want to get rid of Default Adapter and get its funtions into AutoCompleteAdapter.
There are some issues to it: I can no more use the ParentFiles' variables.
Below is the adapter that I want to get rid of.
public class DefaultAdapter extends RecyclerView.Adapter<DefaultAdapter.ViewHolder> {
private Context context;
private AdapterView.OnItemClickListener onItemClickListener;
List<String> searchList;
#NonNull #Override
public DefaultAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = (View) LayoutInflater.from(parent.getContext())
.inflate(android.R.layout.simple_list_item_1, null);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.txt.setText(
Html.fromHtml(getItem(position)).toString());///need to get rid of this error
}
#Override public int getItemCount() {
return searchList.size();
}
#NonNull public String getItem(int position) {
return searchList.get(position);
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView txt;
public ViewHolder(#NonNull View itemView) {
super(itemView);
txt = itemView.findViewById(android.R.id.text1);
itemView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
String title = txt.getText().toString();
searchPresenter.saveSearch(title);
}
});
itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override public boolean onLongClick(View v) {
String searched = txt.getText().toString();
deleteSpecificSearchDialog(searched);
return true;
}
});
}
}
}
Please take note of the SearchPresenter. This is a variable in the parent file, that is causing major issues. Autocomplete adapter doesn't have to use it, but default have to.
This is the adapter I want it to merge into
public class AutoCompleteAdapter extends RecyclerView.Adapter<AutoCompleteAdapter.ViewHolder>
implements Filterable {
#Inject JNIKiwix currentJNIReader;
#Inject SharedPreferenceUtil sharedPreferenceUtil;
#Inject ZimReaderContainer zimReaderContainer;
private List<String> data;
private KiwixFilter kiwifilter;
private Context context;
public AutoCompleteAdapter(Context context) {
this.context = context;
data = new ArrayList<>();
kiwifilter = new KiwixFilter();
setupDagger();
}
private void setupDagger() {
CoreApp.getCoreComponent().inject(this);
}
#NonNull #Override public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = (View) LayoutInflater.from(parent.getContext())
.inflate(android.R.layout.simple_list_item_1, null);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.title.setText(Html.fromHtml(getItem(position)).toString());
}
#Override
public String getItem(int index) {
String a = data.get(index);
if (a.endsWith(".html")) {
String trim = a.substring(2);
trim = trim.substring(0, trim.length() - 5);
return trim.replace("_", " ");
} else {
return a;
}
}
#Override public int getItemCount() {
return data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView title;
public ViewHolder(#NonNull View itemView) {
super(itemView);
title = itemView.findViewById(android.R.id.text1);
}
}
}
...
Note the similarity between the two, they are almost similar, autocompleteadapter is like superset of defaultadapter.
I just want to get rid of the default adapter.
Note: I have chopped off some other things from autocompeleteadapter, I think they are not required for the problem.
Noob here...
Thanks

Inflate multiple layout in FirestoreRecyclerAdapter [duplicate]

My Title is kind of hard to understand but basically when I add items into my database is should display it in a RecyclerView. Now in my RecyclerView I have two layouts but the problem is the first item of my database goes behind my first item in my other layout. So if I have 3 items in my database, it shows only 2 items from the database and the first item hides behind my first item in the RecyclerView which is a different layout that does not use the database at all.
This is my code:
FirebaseRecyclerOptions<Event> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<Event>()
.setQuery(query1, Event.class).build();
AccAdapter = new FirebaseRecyclerAdapter<Event, RecyclerView.ViewHolder>(firebaseRecyclerOptions){
final static int TYPE_HEADER = 0;
final static int TYPE_ITEM = 1;
#Override
public int getItemViewType(int position) {
if (position == 0) return TYPE_HEADER;
return TYPE_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER){
View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_add_items,
parent, false);
return new ProdudctHolder3(view);
} else {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_acc,
parent, false);
return new ProductHolder2(view);
}
}
#Override
protected void onBindViewHolder(final RecyclerView.ViewHolder holder, int position, final Event model) {
if (holder instanceof ProdudctHolder3){
((ProdudctHolder3) holder).addBackground.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(getActivity(), AccAddItems.class ));
}
});
} else{
final ProductHolder2 productHolder2 = (ProductHolder2) holder;
productHolder2.mName.setText(model.getName());
productHolder2.view.setBackgroundResource(getBackgroundDrawable(Integer.valueOf(model.getProductAmount())));
productHolder2.mbackground.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.popup_edit_product);
SeekBar amountSeekBar = dialog.findViewById(R.id.amountSeekBar);
amountSeekBar.setMax(100);
amountSeekBar.setProgress(Integer.valueOf(model.getProductAmount()));
amountSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
progress = i;
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
getRef(holder.getAdapterPosition()).child("productAmount").setValue(String.valueOf(progress));
dialog.dismiss();
}
});
dialog.show();
}
});
productHolder2.mbackground.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
final PopupMenu popupMenu = new PopupMenu(getActivity(), productHolder2.mbackground);
popupMenu.inflate(R.menu.menu_acc);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.deleteProduct:
getRef(productHolder2.getAdapterPosition()).removeValue();
popupMenu.dismiss();
return true;
default:
return false;
}
}
});
popupMenu.show();
return true;
}
});
}
}
};
mAccRecyclerViewRef.setAdapter(AccAdapter);
My two Product Holders
private class ProdudctHolder3 extends RecyclerView.ViewHolder{
private RelativeLayout addBackground;
public ProdudctHolder3(View itemView) {
super(itemView);
addBackground = itemView.findViewById(R.id.mBackground2);
}
}
private class ProductHolder2 extends RecyclerView.ViewHolder{
private TextView mName;
private RelativeLayout mbackground;
private View view;
public ProductHolder2(View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.ItemName);
mbackground = itemView.findViewById(R.id.mBackground1);
view = itemView.findViewById(R.id.amountIndicator);
}
}
The ideal solution would have been to set two adapters on a single RecyclerView but unfortunatelly this is not possible.
However, you can make a single custom Adapter that handles two types of items. I will explain this by getting an example.
Let's assume you need to display objects of two types, humans and aliens. Your objects require completely different layouts and completely different ViewHolders. Please see the below code for the ViewHolders:
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static class HumanViewHolder extends RecyclerView.ViewHolder {
public HumanViewHolder(View itemView) {
super(itemView);
//Prepare your ViewHolder
}
public void bind(Human human) {
//Display your human object
}
}
private static class AlienViewHolder extends RecyclerView.ViewHolder {
public AlienViewHolder(View itemView) {
super(itemView);
//Prepare your ViewHolder
}
public void bind(Alien alien) {
//Display your alien object
}
}
}
First you need to add two different constants to your adapter representing both type of views:
private static final int ITEM_TYPE_HUMAN;
private static final int ITEM_TYPE_ALIEN;
To keep things simple, let's also assume you store your objects in a list:
private List<Object> items = new ArrayList<>();
public MyAdapter(List<Object> items) {
this.items.addAll(items);
//Other stuff if needed
}
Now, the first you need to do, is to implement getItemViewType() method:
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof Human) {
return ITEM_TYPE_HUMAN;
} else {
return ITEM_TYPE_ALIEN;
}
}
Second, you need to use the item type inside the onCreateViewHolder() method like this:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == ITEM_TYPE_HUMAN) {
View view = layoutInflater.inflate(R.layout.item_human, parent, false);
return new HumanViewHolder(view);
} else {
View view = layoutInflater.inflate(R.layout.item_alien, parent, false);
return new AlienViewHolder(view);
}
}
In the end, you just need to bind the proper view holder like this:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
Object item = items.get(position);
if (viewHolder instanceof HumanViewHolder) {
((HumanViewHolder) viewHolder).bind((Human) item);
} else {
((AlienViewHolder) viewHolder).bind((Alien) item);
}
}
Why use the Firebase Recycler Adapter when you could easily make a custom one? If I understood well you want an item to be fixed at position 0 (header) while others will be added below the first one, right? If so, here is a solution I like to use:
public interface ViewType {
public int getViewType();
}
public interface ViewTypeDelegateAdapter {
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item);
}
public class ViewTypes {
public static int HEADER = 0
public static int ITEM = 1
}
public class ProductDelegateAdapter implements ViewTypeDelegateAdapter {
private int resID;
private Context context;
public ProductDelegateAdapter(int resID, Context context) {
this.resID = resID;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new ProductHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
(holder as ProductHolder).bind("test");
}
class ProductHolder extends RecyclerView.ViewHolder {
public ProductHolder(View view) {
super(view);
}
public void bind(String test) {
}
}
}
public class HeaderDelegateAdapter implements ViewTypeDelegateAdapter {
private int resID;
private Context context;
public ProductDelegateAdapter(int resID, Context context) {
this.resID = resID;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new HeaderHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
(holder as HeaderHolder).bind("test");
}
class HeaderHolder extends RecyclerView.ViewHolder {
public HeaderHolder(View view) {
super(view);
}
public void bind(String test) {
}
}
}
public class AccAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private Context context;
private List<ViewType> items;
private SparseArrayCompat<ViewTypeDelegateAdapter> delegateAdapters;
private ViewType headerItem;
public AccAdapter(Context context) {
this.context = context;
this.items = new ArrayList();
this.delegateAdapters = new SparseArrayCompat();
this.headerItem = new ViewType() {
#Override
public int getViewType() {
return ViewTypes.HEADER;
}
};
this.items.add(this.headerItem);
this.delegateAdapters.put(ViewTypes.HEADER, HeaderDelegateAdapter(R.id.test, this.context));
this.delegateAdapters.put(ViewTypes.ITEM, ProductDelegateAdapter(R.id.test, this.context));
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, Int viewType) {
return delegateAdapters.get(viewType).onCreateViewHolder(parent);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, Int position) {
delegateAdapters.get(getItemViewType(position)).onBindViewHolder(holder, items[position])
}
#Override
public Int getItemViewType(Int position) {
return items.get(position).getViewType();
}
#Override
public Int getItemCount() {
return items.getSize();
}
public void add(ViewType viewType) {
val initPosition = this.items.size - 1
this.items.add(item)
notifyItemRangeChanged(initPosition, this.items.size + 1)
}
}
public class Event implements ViewType {
private String id;
#Override
public int getViewType() {
return ViewTypes.ITEM;
}
}
Excuse me for some syntax errors, I've translated to Java from Kotlin to help you. Hope it helps!

FirebaseRecyclerAdapter doesn't recognize first layout as a position

My Title is kind of hard to understand but basically when I add items into my database is should display it in a RecyclerView. Now in my RecyclerView I have two layouts but the problem is the first item of my database goes behind my first item in my other layout. So if I have 3 items in my database, it shows only 2 items from the database and the first item hides behind my first item in the RecyclerView which is a different layout that does not use the database at all.
This is my code:
FirebaseRecyclerOptions<Event> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<Event>()
.setQuery(query1, Event.class).build();
AccAdapter = new FirebaseRecyclerAdapter<Event, RecyclerView.ViewHolder>(firebaseRecyclerOptions){
final static int TYPE_HEADER = 0;
final static int TYPE_ITEM = 1;
#Override
public int getItemViewType(int position) {
if (position == 0) return TYPE_HEADER;
return TYPE_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER){
View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_add_items,
parent, false);
return new ProdudctHolder3(view);
} else {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.recycler_view_row_acc,
parent, false);
return new ProductHolder2(view);
}
}
#Override
protected void onBindViewHolder(final RecyclerView.ViewHolder holder, int position, final Event model) {
if (holder instanceof ProdudctHolder3){
((ProdudctHolder3) holder).addBackground.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(getActivity(), AccAddItems.class ));
}
});
} else{
final ProductHolder2 productHolder2 = (ProductHolder2) holder;
productHolder2.mName.setText(model.getName());
productHolder2.view.setBackgroundResource(getBackgroundDrawable(Integer.valueOf(model.getProductAmount())));
productHolder2.mbackground.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog = new Dialog(getActivity());
dialog.setContentView(R.layout.popup_edit_product);
SeekBar amountSeekBar = dialog.findViewById(R.id.amountSeekBar);
amountSeekBar.setMax(100);
amountSeekBar.setProgress(Integer.valueOf(model.getProductAmount()));
amountSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
progress = i;
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
getRef(holder.getAdapterPosition()).child("productAmount").setValue(String.valueOf(progress));
dialog.dismiss();
}
});
dialog.show();
}
});
productHolder2.mbackground.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
final PopupMenu popupMenu = new PopupMenu(getActivity(), productHolder2.mbackground);
popupMenu.inflate(R.menu.menu_acc);
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.deleteProduct:
getRef(productHolder2.getAdapterPosition()).removeValue();
popupMenu.dismiss();
return true;
default:
return false;
}
}
});
popupMenu.show();
return true;
}
});
}
}
};
mAccRecyclerViewRef.setAdapter(AccAdapter);
My two Product Holders
private class ProdudctHolder3 extends RecyclerView.ViewHolder{
private RelativeLayout addBackground;
public ProdudctHolder3(View itemView) {
super(itemView);
addBackground = itemView.findViewById(R.id.mBackground2);
}
}
private class ProductHolder2 extends RecyclerView.ViewHolder{
private TextView mName;
private RelativeLayout mbackground;
private View view;
public ProductHolder2(View itemView) {
super(itemView);
mName = itemView.findViewById(R.id.ItemName);
mbackground = itemView.findViewById(R.id.mBackground1);
view = itemView.findViewById(R.id.amountIndicator);
}
}
The ideal solution would have been to set two adapters on a single RecyclerView but unfortunatelly this is not possible.
However, you can make a single custom Adapter that handles two types of items. I will explain this by getting an example.
Let's assume you need to display objects of two types, humans and aliens. Your objects require completely different layouts and completely different ViewHolders. Please see the below code for the ViewHolders:
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static class HumanViewHolder extends RecyclerView.ViewHolder {
public HumanViewHolder(View itemView) {
super(itemView);
//Prepare your ViewHolder
}
public void bind(Human human) {
//Display your human object
}
}
private static class AlienViewHolder extends RecyclerView.ViewHolder {
public AlienViewHolder(View itemView) {
super(itemView);
//Prepare your ViewHolder
}
public void bind(Alien alien) {
//Display your alien object
}
}
}
First you need to add two different constants to your adapter representing both type of views:
private static final int ITEM_TYPE_HUMAN;
private static final int ITEM_TYPE_ALIEN;
To keep things simple, let's also assume you store your objects in a list:
private List<Object> items = new ArrayList<>();
public MyAdapter(List<Object> items) {
this.items.addAll(items);
//Other stuff if needed
}
Now, the first you need to do, is to implement getItemViewType() method:
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof Human) {
return ITEM_TYPE_HUMAN;
} else {
return ITEM_TYPE_ALIEN;
}
}
Second, you need to use the item type inside the onCreateViewHolder() method like this:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
if (viewType == ITEM_TYPE_HUMAN) {
View view = layoutInflater.inflate(R.layout.item_human, parent, false);
return new HumanViewHolder(view);
} else {
View view = layoutInflater.inflate(R.layout.item_alien, parent, false);
return new AlienViewHolder(view);
}
}
In the end, you just need to bind the proper view holder like this:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
Object item = items.get(position);
if (viewHolder instanceof HumanViewHolder) {
((HumanViewHolder) viewHolder).bind((Human) item);
} else {
((AlienViewHolder) viewHolder).bind((Alien) item);
}
}
Why use the Firebase Recycler Adapter when you could easily make a custom one? If I understood well you want an item to be fixed at position 0 (header) while others will be added below the first one, right? If so, here is a solution I like to use:
public interface ViewType {
public int getViewType();
}
public interface ViewTypeDelegateAdapter {
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item);
}
public class ViewTypes {
public static int HEADER = 0
public static int ITEM = 1
}
public class ProductDelegateAdapter implements ViewTypeDelegateAdapter {
private int resID;
private Context context;
public ProductDelegateAdapter(int resID, Context context) {
this.resID = resID;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new ProductHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
(holder as ProductHolder).bind("test");
}
class ProductHolder extends RecyclerView.ViewHolder {
public ProductHolder(View view) {
super(view);
}
public void bind(String test) {
}
}
}
public class HeaderDelegateAdapter implements ViewTypeDelegateAdapter {
private int resID;
private Context context;
public ProductDelegateAdapter(int resID, Context context) {
this.resID = resID;
this.context = context;
}
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
return new HeaderHolder(LayoutInflater.from(parent.context).inflate(resID, parent, false));
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, ViewType item) {
(holder as HeaderHolder).bind("test");
}
class HeaderHolder extends RecyclerView.ViewHolder {
public HeaderHolder(View view) {
super(view);
}
public void bind(String test) {
}
}
}
public class AccAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private Context context;
private List<ViewType> items;
private SparseArrayCompat<ViewTypeDelegateAdapter> delegateAdapters;
private ViewType headerItem;
public AccAdapter(Context context) {
this.context = context;
this.items = new ArrayList();
this.delegateAdapters = new SparseArrayCompat();
this.headerItem = new ViewType() {
#Override
public int getViewType() {
return ViewTypes.HEADER;
}
};
this.items.add(this.headerItem);
this.delegateAdapters.put(ViewTypes.HEADER, HeaderDelegateAdapter(R.id.test, this.context));
this.delegateAdapters.put(ViewTypes.ITEM, ProductDelegateAdapter(R.id.test, this.context));
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, Int viewType) {
return delegateAdapters.get(viewType).onCreateViewHolder(parent);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, Int position) {
delegateAdapters.get(getItemViewType(position)).onBindViewHolder(holder, items[position])
}
#Override
public Int getItemViewType(Int position) {
return items.get(position).getViewType();
}
#Override
public Int getItemCount() {
return items.getSize();
}
public void add(ViewType viewType) {
val initPosition = this.items.size - 1
this.items.add(item)
notifyItemRangeChanged(initPosition, this.items.size + 1)
}
}
public class Event implements ViewType {
private String id;
#Override
public int getViewType() {
return ViewTypes.ITEM;
}
}
Excuse me for some syntax errors, I've translated to Java from Kotlin to help you. Hope it helps!

Getting blank RecyclerView inside ConstraintLayout

I'm trying to use CardView , inside the CardView i placed UI widgets 2 TextViews and 2 ImageViews. My RecyclerView is used to display a list of Cardviews
Here's my Java Class model:
public class Masar {
public String masarName;
public String masarDesc;
public int imgl;
public Masar(String masarName, String masarDesc) {
this.masarName = masarName;
this.masarDesc = masarDesc;
}
public Masar(String masarName, String masarDesc, int imgl) {
this.masarName = masarName;
this.masarDesc = masarDesc;
this.imgl = imgl;
}
public String getMasarName() {
return masarName;
}
public String getMasarDesc() {
return masarDesc;
}
public int getImgl() {
return imgl;
}
}
And here's my Adapter class:
public class MasarAdapter extends RecyclerView.Adapter<MasarAdapter.MyViewHolder> {
private Context mContext;
private List<Masar> masrList;
public MasarAdapter(Context mContext, List<Masar> masrList) {
this.mContext = mContext;
this.masrList = masrList;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.masar_items, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Masar masar=masrList.get(position);
holder.masarName.setText(masar.getMasarName());
holder.masarDesc.setText(masar.getMasarDesc());
}
#Override
public int getItemCount() {
return 0;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView masarName, masarDesc;
public ImageView masarImg;
public MyViewHolder(View itemView) {
super(itemView);
masarName = (TextView) itemView.findViewById(R.id.masarName);
masarDesc = (TextView) itemView.findViewById(R.id.masarDesc);
masarImg = (ImageView) itemView.findViewById(R.id.imageView4);
}
}
}
I've tried several times to find out why i'm getting blank result .. Could you please help to solve my problem ?
You're returning 0 in your getItemCount() method.
#Override
public int getItemCount() {
return 0;
}
It should be:
#Override
public int getItemCount() {
return masrList.size();
}

Categories

Resources