I want to create recycler view with heterogenous rows.
Some rows will have imageview, some will have 5 textviews, some will have edit texts, some will have nested recycler views etc.
There is no pattern. How to do this?
What I researched and found :-
AirBnb Epoxy.
Please give some suggestion on how to proceed further with this.
If you have something like:
public class MyRecyclerAdapter extends RecyclerView.Adapter<CustomRecycleViewHolder> then you must override a method named onCreateViewHolder. There are 2 arguments in this method ... one is the ViewGroup parent and the other one is int viewType.
You can change the whole row by checking viewType before creating new Holder.
For example:
if(viewType == 0){
return new MyViewHolder(context,layoutInflater.inflate(R.layout.my_view_holder,null,false));
} else {
return new My2ViewHolder(context,layoutInflater.inflate(R.layout.my_2_view_holder,null,false));
}
Just don't forget that each ViewHolder must extend CustomRecycleViewHolder.
You can implement your own ViewTypes as suggested. But I would suggest Epoxy is a good solution if you have multiple heterogeneous rows. Epoxy is very flexible and provides a lot of functions to build a heterogeneous RecyclerView out of the box. I have used it in multiple large-scale apps and it works really fine.
Instead of creating and keeping track of a lot of ViewHolders, you could just simply create models and use them like
headerModel
.title("My Photos")
.description("My album description!")
.addTo(this);
new PhotoModel()
.id(photo.id())
.url(photo.url())
.addTo(this);
Related
I am using kotlin and I am starting to understand how a recyclerview with multiple view types works.
From what i understand, there are two methods
To create multiple Viewholder and use a when statement (Java switch) in the OnCreateViewHolder to differentiate when what viewholder should be used. -> also overriding the getItemViewType function and bind the data in the OnBindViewHolder.
To make multiple adapters (for each viewtype one) and use adapter concatenate or whatever it was called.
Now what i want to know is when should i use what method? What is better for my app i am coding? Is one method better then the other?
Can someone explain me when to use what method?
Generally speaking you create 1 adapter and different viewHolders. Every viewHolder serves it's viewtype and has it's own inflated xml.
Every item of the list that you are feeding to your adapter has to have a viewType, so when you are about to "draw" a list item you send it to the correct viewHolder to inflate it.
Do not use more than one adapters, it will get messy and hard to maintain.
I'm a swift developer and I was able to build this layout very easily using a UICollectionView. However, I'm struggling to do the same in Kotlin. I've been trying to use a Recycler View to do this but it's not working out. Any advice on how I can do this would be highly appreciated.
I can help you with a few suggestions as to how I would be making this layout. Check if it's of any help:
First, follow this post for implementing multiple viewtypes in your recyclerview by overriding getItemViewType() method in your recyclerview adapter. You can set the item's viewtype based on its position in the datalist or a value in your datasource etc. Based on this viewtype returned you can set what your viewholder should look like in the adapter's onCreateViewHolder() and the funtionality in onBindViewHolder() method.
Next your recyclerview will need to make use of a GridLayoutManager with vertical orientation and 2 columns.
With these 2 steps you can have multiple views in different columns as you require, BUT in order to have a viewholder occupy whole width like the 2nd row in your sample image you will need to make use of setSpanSizeLookup() method of your grid layout manager. You can use this post here for reference.
Basically this is all you need to achieve your layout. Make use of multiple viewtypes for recyclerview with a gridlayout manager having a custom spansize lookup.
The references i mentioned are mostly in java but converting them to kotlin should be fairly easy. Have a look and let us know if this helps.
I have a for loop within a for loop within a for loop (3 for loops). Each for loop loads at least one view in them some load more than 1. All of the views(textviews, imageviews) are loaded into a relative layout or a linear layout and those layouts are all loaded into one linear layout and all of that is in a scrollview.
I know confusing and probably the worst way to do this. I have looked up different things most of them are listview related such as the endless adapter or lazy loading. I don't think listview will work for what i am trying to do. I have memory problems doing it this way.
So I guess what my question is will ListView be the right direction to go? Will i still be able to use my for-for-for loops?
Consider each block to represent a layout (each of layout consist of textviews, only the black boxes have imageviews and textviews) and also consider each color to represent a for loop. The black borders represent the linear layout that all of these views and other layouts get shoved into. Keep in mind it's not always going to be the same amount of black boxes beneath the red and blue boxes
i don't know if i really got what you want do here but in my opinion u should use an Adapter.
Doing this with layouts as you stated cause memory problems because you are loading a complex hierarchy of views, android is drawing all the views (even the ones that are not visible yet) and none of your views are reused.
Using a ListView and defining different types of AdapterView you should be able to do what you need.
For instance lets say each red box is one AdapterView. So from your scheme you'll have 2 AdapterView, lets call them "ViewOneBlueTwoBlack" and "ViewOneBlueThreeBlack". Also lets say you have more types of AdapterViews "ViewTwoBlueTwoBlack", "ViewTwoBlueFiveBlack", etc...
Now what you need to do is handle in your Adapter the conditions to know when each type of AdapterView should be load.
Or even better if you consider that the redboxes are sections and then the blue boxes become your AdapterViews.
You can find a nice tutorial on ListViews and Adapter here : http://www.vogella.com/tutorials/AndroidListView/article.html
Also your scheme looks a lot like a ExpandableListView check it out just in case.
You should definitly used a ListView and an adpater.
You can have diffenet view type in your ListView. To do so you should have an adapter like this :
public class YourAdapter extends BaseAdapter {
private static int HEADER_TYPE = 0;
private static int CONTENT_TYPE_1 = 1;
private static int CONTENT_TYPE_2 = 2;
#Override
public int getViewTypeCount() {
return 3;
}
#Override
public int getItemViewType(int position) {
if (header)
return HEADER_TYPE;
else if (content_type_1)
return CONTENT_TYPE_1;
else
return CONTENT_TYPE_2;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == HEADER_TYPE) {
//make header view
} else if (getItemViewType(position) == CONTENT_TYPE_1 {
//make content view
//be careful position is the position in the list view
} else {
//make content view
//be careful position is the position in the list view
return convertView;
}
}
You should be careful when accessing your datas in getView, the postion is the position in the ListView.
I would suggest you to use a table layout for this. Declare a table layout in your xml file, and add views dynamically.
I gave a similar answer here, you can customize the solution to have only one view in row and align accordingly.
"So I guess what my question is will ListView be the right direction to go? Will i still be able to use my for-for-for loops?"
Answer is, right direction depends upon your scenario if your objective can be achieved with both then see which method has least views or widgets in your case there are many layouts but if you use ListView there might be one. Bt in developing the best way is any way which fullfil customer's requirements..
I have decided to upgrade my code to use RecyclerView now instead of the list I am using now.
As I understand the following is how it normally goes:
onCreateViewHolder - this inflates a view, and does the findviewbyid and returns it as a ViewHolder object for the view
onBindViewHolder - this assigns the view holder values to the position view (which is being recycled).
This is all fine and dandy... If the views in the list contain the same fields...
My views however in my list are different, before I programmatically added views depending on the adapter List (in the getView method).
Is there a "good practice" way to handle this, I can't think of a good way to get around this.
getViewItemType does not work as the views are unique and that they are not predefined.
This is what you need to use when you different types of Views inside a ListView or RecyclerView :-
getItemViewType() and getViewTypeCount()
First you need to use getViewTypeCount() and return the number of unique views you need inside your List. Then override getItemViewType() and return the View type you want to inflate inside the List row.
Hope it will help.
If you still have any issue and need a working example, let me know, i'll update my answer.
I was wondering how to show the snapshot of my notes, checklists, images in the grid view. I have no trouble creating the grid view but creating a preview of it is the challenge I'm facing right now as I need to add different type of views(text, checklist, imageview) to the grid according to their time of creation. Works fine for a single type of view like image or text only.
Or in other words. How do I add the different views dynamically to the GridView Adapter?
All or any help is appreciated.
Thanks.
They surely do not use a GridView for google Keep - but probably an Adapter nonetheless.
To use different Views with your Adapter you can use different View types:
Override getViewTypeCount() to return the number of View types you support.
Return the appropriate type in getItemViewType(int position) for this specific item.
Create the correct View in getView(int position, View convertView, ViewGroup parent).
Keep in mind that the rules for recycling, ViewHolder and so on still apply. For multiple types recycling only happens for the correct type.
Marcus Körner shared a gist by Jake Wharton on G+ recently that might be useful.
More than likely Google is using something similar to GridLayout, if not actually using a GridLayout.
Chances are the layout is also created programmatically to allow for the widgets to be different sizes based on the content that they each display.
Take a look at this recycle view with stagged
This manage make all what you need StaggeredGridLayoutManager
or look at this sorce Heterogenous Layouts inside RecyclerView
recyclerView= (RecyclerView) findViewById(R.id.recycler);
recyclerView.setLayoutManager(new
StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));
initData();
MasonryAdapter adapter=new MasonryAdapter(productList);
recyclerView.setAdapter(adapter);
SpacesItemDecoration decoration=new SpacesItemDecoration(16);
recyclerView.addItemDecoration(decoration);