How to optimise list view with multiple layouts - android

I am trying to determine the best way to have a single listview contains different rows styles. I know how to create a custom row + custom array adapter to support a custom row for the entire list view. But how can one listview support many different row styles?

Since you know how many types of layout you would have - it's possible to use those methods.
getViewTypeCount() - this methods returns information how many types of rows do you have in your list
getItemViewType(int position) - returns information which layout type you should use based on position
Then you inflate layout only if it's null and determine type using getItemViewType.
Look at this tutorial for further information.
To achieve some optimizations in structure that you've described in comment I would suggest:
Storing views in object called ViewHolder. It would increase speed because you won't have to call findViewById() every time in getView method. See List14 in API demos.
Create one generic layout that will conform all combinations of properties and hide some elements if current position doesn't have it.
I hope that will help you. If you could provide some XML stub with your data structure and information how exactly you want to map it into row, I would be able to give you more precise advise. By pixel.

You have to write you custom adapter which extends BasaAdapter. NOTE: viewTypeCount(). Then you can use condition to check and assign different views
private class MyAdapter extends BaseAdapter{
public static final int ITEM_TYPE_ONE = 1;
public static final int ITEM_TYPE_TWO = 2;
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
return (position % 2 == 0) ? ITEM_TYPE_ONE : ITEM_TYPE_TWO;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
int itemTypeId = getItemViewType(position);
if (convertView == null) {
if (itemTypeId == ITEM_TYPE_ONE) {
convertView = inflater.inflate(R.layout.layout_one, parent, false);
} else {
convertView = inflater.inflate(R.layout.layout_two, parent, false);
}
}
}
}

Just create an attribute and myListView.addView('your inflate view')
LayoutInflater inflater = LayoutInflater.from(this);
RelativeView myCustomView =(RelativeView)inflater.inflate(R.layout.task_since_user);
myListView.addView(myCustomView);

Related

How to design Gridview like guardian app

I am trying to make layout like guardian app. I know what is gridview and how to design it and inflate it with data etc.
what i want to design?
This layout have items with images and not with and there is also lazy loading going on in it.
What are the problem i am facing?
1-Confused which viewi should i go with. GridView,ListView or
RecyclerView.
2-if i go with GridView then how to have different item layouts for
some items.
What i have tried?
I have tried using linear layout as seperate xml and then i add that xml to root layout on run time. it works somewhat but problem rise when i need to add clicklistener to show relevent post since there would be more than 100+ post data.
It would be a lot of help if somebody guide me in right direction. Thanks!
EDIT. After going through the answer here. I used this approach. I used to xml. Then i change the layout with getViewType in adapter but that doesn't give such results. I am still looking for more convincing solution.
Here is the code that i have tired.
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder>{
MainDTO mainDTO;
public RecyclerAdapter(MainDTO mainDTO){
this.mainDTO=mainDTO;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
ViewHolder viewHolder;
switch (viewType){
case 0:
view= LayoutInflater.from(parent.getContext()).inflate(R.layout.header,parent,false);
viewHolder=new ViewHolder(view,viewType);
return viewHolder;
default:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.box,parent,false);
viewHolder=new ViewHolder(view,viewType);
return viewHolder;
}
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
ImageLoader imageLoader = ImageLoader.getInstance();
if(position == 0){
imageLoader.displayImage(mainDTO.getPosts().get(position).getThumbnail_images().getFull().getUrl(),holder.thumbnail);
holder.title.setText(mainDTO.getPosts().get(position).getTitle());
}
else if (position > 0 ){
if(mainDTO.getPosts().get(position).getThumbnail_images()!=null)
imageLoader.displayImage(mainDTO.getPosts().get(position).getThumbnail_images().getFull().getUrl(),holder.thumbnail);
holder.title.setText(mainDTO.getPosts().get(position).getTitle());
}
}
#Override
public int getItemCount() {
return mainDTO.getPosts().size();
}
#Override
public int getItemViewType(int position) {
int viewType = 1; //Default is 1
if (position == 0) viewType = 0; //if zero, it will be a header view
return viewType;
}
public static class ViewHolder extends RecyclerView.ViewHolder{
public TextView title;
public ImageView thumbnail;
public ViewHolder(View itemView,int viewType) {
super(itemView);
if(viewType == 0){
title = (TextView)itemView.findViewById(R.id.tv_title);
thumbnail = (ImageView)itemView.findViewById(R.id.iv_thumbnail);
}else if(viewType == 1){
title = (TextView)itemView.findViewById(R.id.tv_title_2);
thumbnail = (ImageView)itemView.findViewById(R.id.iv_thumbnail_2);
}
}
}
}
You will need to use StaggeredGridLayoutManager with RecyclerView to achieve what is being done in the guardian app. See this link StaggeredGridLayoutManager Tutorial
Edit 1
I have written a small sample application which can demonstrate what guardian application is achieving. Here is the Github link. I will explain it along the way with each step:
I used a StaggerdGridLayoutManager since in guardian app you are referring to have occupied different cell heights. This layout enables us to have items with different height.
For every different view type we have to create different view holders. For instance I have created 3 different view holders for every different item type in the sample application.
Override getItemViewType to let the recyclerview adapter know which view to inflate.
For instance of sample, I stored my data objects in an List of type Object to store heterogeneous objects and checked every item if its an instance of a particular class. I created 3 different types:
#Override
public int getItemViewType(int position) {
// we check here which item type to return based on object type
if (items.get(position) instanceof ImageModel)
return ITEM_TYPE_IMAGE;
if (items.get(position) instanceof TextViewModel)
return ITEM_TYPE_TEXT;
if (items.get(position) instanceof ButtonModel)
return ITEM_TYPE_BUTTON;
return -1;
}
Get itemViewType for the current view holder in OnCreateViewHolder in order to determine which layout to inflate.
For the instance of sample:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType){
case ITEM_TYPE_IMAGE:
View image = ((LayoutInflater)BaseApplication.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.item_image, parent, false);
return new ImageViewHolder(image);
case ITEM_TYPE_BUTTON:
View button = ((LayoutInflater)BaseApplication.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.item_button, parent, false);
return new ButtonViewHolder(button);
case ITEM_TYPE_TEXT:
View text = ((LayoutInflater)BaseApplication.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.item_text, parent, false);
return new TextViewHolder(text);
}
return null;
}
Make specific type of items cover full row span.
Since some posts types are occupying full span in guardian application, we can use below code in OnBindViewHolder method to make any item expand to full span of layout.
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == ITEM_TYPE_IMAGE){
StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
layoutParams.setFullSpan(true);
}
}
This makes the item cover all the span of layout like the biggest post in guardian application.
By following above steps, you can create a similar layout like this (image from sample github application):
Here there are 3 different item types: above two items are Buttons, middle one is ImageView and bottom are TextView.
You can use recycler view with GridLayoutManager. And In your adapter make different layout type as per your requirements.
GridLayoutManager manager = new GridLayoutManager(getActivity(), 6);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
// return your span size as per your layout type.
return 6;
}
}
});
Go to this for more info.
Edit:
Follow my github demo
There is three different kinds of views, one large grid, two small grids and 3-4 list view items. It is hard to use only one kind of view to complete such a task.
I suggest you to create some custom views to handle the grids (large and small), and a list view to handle the list item. After that, you can reuse the custom views for the grids and the list view's custom adapter in other sessions.
If you really want to use one Grid view to handle different views, then create a generic view that has all the functions and disable/enable the functions when you needed. However, this is much more complicated.
You can use RecyclerView because it gives you method to define different item types. but still to create such view you have to do so much code on the basis of its layout.
You have to override getItemViewType method and try to find which view type will be next to display. example code
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position))
return TYPE_HEADER;
return TYPE_ITEM;
}
Hope this will help
You require: Asymmetric Gridview
https://github.com/felipecsl/AsymmetricGridView
Above link will help.
You can define a common onClickListener
I will explain You How to do instead of writing the whole code we will use Recylerview for it
Recylervew which have four Items (Item1,Item2,Item3,Item4)
Item1 : it will contains the View1
Item2 : It will contains the VIew2
Item3 : It will contains the VIew3
Item4 : It will contains the VIew4
View1 : It will contains one Layout for text and other layout for comment and day section
View2 : It will contain the Image View
View3 : It will contains the tablelayout with one row and two columns
View4 : It will contains the linearlayout
TO achieve above layout design, you need to use recyclerView with StaggaredGridLayoutManager.
You have to use RecyclerView with StaggeredGridLayoutManager.

ListView and it's "weird" behavior. How can i solve this situation?

As you should know, ListView recycles the view. But i want to work with elements that can be clicked and expanded. Like i already did:
But it was completely messed up, even using:
View checklayout = convertView;
if(checklayout == null){
checklayout = inflater.inflate(R.layout.home_cell, null);
}
When some opened expandable views goes out of the screen, the recycled one, which shouldn't be expandable, receives the vanished's layout. Only view that has "1 AVALIAÇÃO LANÇADA" should open, and show it's content. I add this content by using if(qtdAvaliacoes > 0) that is a property of my Object that comes from ArrayList<>.
I "solved" this disabling the recycler, with:
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
Once my listView will only receives 5~10 rows. But i know that isn't a good practice. While i'm writting this question, i found a solution, calling my object before inflate any view, then checking the property:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View checklayout = convertView;
final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final Disciplina disciplina = lista.get(position);
if(checklayout == null || disciplina.getQtdAvaliacoes() == 0){
checklayout = inflater.inflate(R.layout.home_cell, null);
}
final View layout = checklayout;
But I don't think this is the best way to do this. I read something about Tags, but was little confused. I think if i could bind these onClick methods to the row position it would be better.
Any ideas ? Or is my solution good at you, developer's, point of view.
Thanks.
The easiest way is to not do subinflates within a list item. Do it via view visibilities instead, making the inflated part GONE if you don't want it to display yet. You'll just have to explicitly set the visibility of that view in every call to getView

Set up ListView from a String[][]

I have a String[][] of data and I am trying to make a custom listView from it.
Here is the data
String[][] myDataArray = {{"cat1","cat2","cat3","cat4"},
{"dog1","dog2","dog3"},
{"lion1"},
{"monkey1","monkey2"}};
And now here is how I am trying to display this data in my listView. I want each array within the array to have its own row. So all the cats will be in one row (cell), all the dogs will be in another row and so on. Here is a picture to make it clear each item in the row, is a textView.
I have made cell_4.xml, cell_3.xml, cell_2.xml, cell_1.xml layout file for each of the rows.
And then in the activity that I am trying to show this, I just have a plain old listView.
Now I am not quite sure how to edit/ adapt the data. I have to display it in this way. So that it uses the correct cell layout for each array within the String[]. I was thinking about using a switch statement to get the number of items in each inner array. But having some trouble with the ArrayAdapter. To get it set up.
I have looked at a couple of examples on stackoverflow like this one Custom ListView Android to try and figure this out but can't get it.
EDIT
Here is trying to set up adapter and call MyListViewAdapter, but I don't know what to set as context.
here is the code:
private void handleData(String[][] data){
BaseAdapter adapter = MyListAdapter(context, data);
ListView list = (ListView) findViewById(R.id.mealsListView);
list.setAdapter(adapter);
}
Some thoughts:
1) If you are determined to use ListView, skip this point. Else, you might be interested in GRIDVIEW that natively support a table structure.
2) Your idea is consistent. ListView only knows about ROWS, so your adapter will be called for you to display a ROW, and it's up to you to transform the array in that row into an element with multiple cells. You'll do that in getView()
3) You'll make use of the Item Types (getViewTypeCount and getItemViewType) to declare you have different item types. Each type will be a row with a given number of cells: 1,2,3,4...
you will override getViewTypeCount() to return the maximum number of cells in a row
you will either inflate a static layout for the number of cells a row has, or generate it dynamically
Let's get started ... First of all in the adapter we override the Type methods to declare
our rows will be of different types:
#Override
public int getViewTypeCount() {
return 4;
// you have 4 types of rows.
// SUPER IMPORTANT: No row in the array can have more cells than this number
// or getView will crash (you'd have to define additional layouts)
}
#Override
public int getItemViewType(int position) {
// for a given position, you need to return what type is it. This number ranges
// from 0 to itemtypecount-1. We return the length of the array (number of cells)
// this function is called by the View Recycler to appropriately pass you the
// correct view to reuse in convertView
return myDataArray[position].length - 1;
}
And then we need to implement getView(). The typical implementation will be the first one, where you create different XMLs, and the second one is a more advanced implementation where we dynamically create the layouts without any xml.
First Case: Static Layouts
Ideal if you limit the Row Array Length to say 3 or 4, to avoid creating dozens of layouts. So you define 4 xmls (ie. row_1_childs, row_2_childs, row_3_childs, row_4_childs) that will be the templates of rows with that number of children. Then,
and then in GetView:
// we define an array of layout ids to quickly select the layout to inflate depending on
// the number of rows:
private final static int[] sLayouts=new int[] {
R.layout.row_1_childs,
R.layout.row_2_childs,
R.layout.row_3_childs,
R.layout.row_4_childs
};
public View getView (int position, View convertView, ViewGroup parent) {
int maxcells=myDataArray[position].length;
if (convertView == null) {
// generate the appropriate type
if (maxcells<=sLayout.length) {
// just check we are in bounds
convertView=LayoutInflater.from(parent.getContext()).inflate(sLayout[maxcells-1], null);
} else {
// you have a row with too many elements, need to define additional layouts
throw new RuntimeException ("Need to define more layouts!!");
}
}
// At this point, convertView is a row of the correct type, either just created,
// or ready to recycle. Just fill in the cells
// for example something like this
ViewGroup container=(ViewGroup)convertView;
for (int i=0; i<maxcells; i++) {
// We assume each row is a (linear)layout whose only children are textviews,
// one for each cell
TextView cell=(TextView)container.getChildAt(i); // get textview for cell i
cell.setText(myDataArray[position][i]);
cell.setTag( new PositionInfo(position, i)); // we store the cell number and row inside the TextView
cell.setOnClickListener(mCellClickListener);
}
return convertView;
}
Second Case: Dynamic Layouts
Another solution would be to dynamically generate the rows, and dynamically generate as many text views as you might need. To do so, keep overriding getViewTypeCount() to return the Maximum number of children, and define getView like this:
public View getView (int position, View convertView, ViewGroup parent) {
String rowData=myDataArray[position];
if (convertView==null) {
// generate a LinearLayout for number of children:
LinearLayout row=new LinearLayout(context);
for (int i=0, len=rowData.length(); i<len; i++) {
// generate a textview for each cell
TextView cell=new TextView(parent.getContext());
// we will use the same clicklistener (very efficient)
cell.setOnClickListener(mCellClickListener);
row.addView(cell, new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1)); // same width for each cell
}
convertView=row;
}
// here convertView has the correct number of children, same as before:
ViewGroup container=(ViewGroup)convertView;
for (int i=0, len=rowData.length(); i<len; i++) {
TextView cell=(TextView)container.getChildAt(i);
cell.setText(rowData[i]);
cell.setTag( new PositionInfo(position, i)); // we store the cell number and row inside the TextView
}
return convertView;
}
// auxiliar class to store row and col in each textview for the clicklistener
private class PositionInfo {
public int row, col;
public PositionInfo(int row, int col) { this.row=row; this.col=col; }
}
// trick: only one clicklistener for millions of cells
private View.OnClickListener mCellClickListener=new View.OnClickListener() {
#Override
public void onClick(View v) {
PositionInfo position=(PositionInfo)v.getTag(); // we stored this previously
// you pressed position.row and position.col
}
}
Solution (1) is cool to manually create the layouts and configure them a lot.
Solution (2) is cool to programmatically support any number of cells, in case they are very different
Both solutions are pretty efficient, because they play nice with the View recycler: If you fail to use View Types and you constantly inflate layouts, your ListView will be laggy and waste a lot of memory and resources.
You might run into problems if the size of each string in the row varies and you might then have to push data onto the next line.
Try using an alternate view, if your aim is categorization of similar data, expandable listview is an option to consider.
You will need to make your own adapter by extending BaseAdapter. You can check the data's size the getView() method, and inflate the correct layout.
UPDATE:
public class MyListAdapter extends BaseAdapter{
String[][] mData;
LayoutInflater mLayoutInflater;
public MyListAdapter(Context context, String[][] data) {
mData = data;
mLayoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return mData.length;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String data[] = mData.get(position);
switch(data.length){
case 4:
convertView = mLayoutInflater.inflate(R.layout.cell_4, parent, false);
TextView t1 = (TextView) convertView.findViewById(R.id.one);
t1.setText(data[0]);
break;
case 3:
convertView = mLayoutInflater.inflate(R.layout.cell_3, parent, false);
break;
case 2:
convertView = mLayoutInflater.inflate(R.layout.cell_2, parent, false);
break;
case 1:
convertView = mLayoutInflater.inflate(R.layout.cell_1, parent, false);
break;
default:
convertView = mLayoutInflater.inflate(R.layout.blank, parent, false);
}
return convertView;
}
}

Add a different element to ArrayAdapter/ListView

I have a ListView that's being populated by an ArrayAdapter:
someListView.setAdapter(adapter);
Each element in the adapter is inflated using the same layout.xml. Now I want to add an element of a different type (inflated using a different layout file) to the beginning of the ListView.
What I want to achieve is, to have a special element on top of all other elements in the list view, but also scrolls with the list (exits the screen from top if the user scrolls down).
I've tried to add the new element to the array but it's a different type so that won't work.
I've tried to insert a dummy element to the array at position 0, and modify the adapter's getView() so that if (position == 0) return myUniqueView, but that screwed up the entire list view somehow: items not showing, stuff jumping all over the place, huge gaps between elements, etc.
I start to think the best practice of achieving what I want, is not through editing the array adapter. But I don't know how to do it properly.
You don't need anything special to do what you ask. Android already provides that behavior built in to every ListView. Just call:
mListView.addHeaderView(viewToAdd);
That's it.
ListView Headers API
Tutorial
Do't know exactly but it might usefull
https://github.com/chrisjenx/ParallaxScrollView
In your adapter add a check on the position
private static final int LAYOUT_CONFIG_HEADER = 0;
private static final int LAYOUT_CONFIG_ITEMS = 1;
int layoutType;
#Override
public int getItemViewType(int position) {
if (position== 0){
layoutType = LAYOUT_CONFIG_HEADER;
} else {
layoutType = LAYOUT_CONFIG_ITEMS;
}
return layoutType;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
LayoutInflater inflater = null;
int layoutType = getItemViewType(position);
if (row == null) {
if (layoutType == LAYOUT_CONFIG_HEADER) {
//inflate layout header
}
} else {
//inflate layout of others rows
}
}

ListView Adapter with arbitrary number of row types (Don't know the number of different row types)

So, I am making this application. The application parses a website, or more specifically a vbulletin-board. When I'm parsing a thread in the forum, I have divided it up so that when I parse each post in that thread, I get the actual content of the post in sections such as this, and I store the sections in the correct order in an array:
[Plain text]
[Quote from somebody]
[Plain text]
[Another quote]
[Another quote again]
[Some more plain text]
However, a post can be arranged in any order as you might know, and can consist of more or fewer sections than in the example, and it doesn't have to have quotes in it either, or it might just be one or several quotes. Anything is possible.
When I list the posts in my application, I am using a ListView. Each row of this listview will then always consist of a header, and any combination of the previously mentioned sections.
The way I was thinking of doing it after googling a bit about it is to have one "Base-layout" with just a layout-tag in one XML-file, and a separate layout for each section, stored in separate XML-files, and at each call to getView() in my adapter, look at the post at that position in my "Post-list", and then loop through the sections in that particular post, and inflate a new "Quote-layout" for each quote-section stored in the post, and inflate a "Plain-text-layout" for each plain-text-section in the post. And for each of those I fill in all the content belonging to that post.
I think this would work, but there might be a performance problem? As I understand it layout inflation is quite expensive, and I won't be able to recycle the View passed in to getView() either, since it might have a bunch of sections added to it that I might not need in another call to getView().. That is, if I understand getView() and the recycling somewhat.
This is a basic example of what I mean with the getView() method of the adapter:
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
// Inflate the base-layout, which the others are added to.
view = mInflater.inflate(R.layout.forum_post,null);
View header = mInflater.inflate(R.layout.post_header_layout, null);
View message = mInflater.inflate(R.layout.post_text_layout, null);
View quote = mInflater.inflate(R.layout.post_quote_layout, null);
((ViewGroup)view).addView(header);
((ViewGroup)view).addView(message);
((ViewGroup)view).addView(quote);
return view;
}
And then inflate more quote-views/message-views as needed when I extract the data from my list of saved posts.
The base-layout is just a LinearLayout-tag
The layouts I inflate are just RelativeLayouts with some TextViews and an ImageView added.
This code produces this result, where I have a Header with
username, picture, etc.., One section of Plain text, and one Quote-section.
This doesn't seem to work properly all the time though, because when I tried it out just now a copy of the list seemed to get stuck on the background and another one scrolled on top of it..
http://s14.postimg.org/rizid8q69/view.png
Is there a better way to do this? Because I imagine this isn't very efficient
You need to override getViewItemType and getViewTypeCount.
getItemViewType(int position) - returns information which layout type you should use based on position
Then you inflate layout only if it's null and determine type using getItemViewType.
Example :
private static final int TYPE_ITEM1 = 0;
private static final int TYPE_ITEM2 = 1;
private static final int TYPE_ITEM3 = 2;
#Override;
public int getItemViewType(int position)
{
int type;
if (position== 0){ // your condition
type = TYPE_ITEM1; //type 0 for header
} else if(position == 1){
type = TYPE_ITEM2; //type 1 for message
}else {
type = TYPE_ITEM3; //type 2 for Quote
}
return type;
}
#Override
public int getViewTypeCount() {
return 3; //three different layouts to be inflated
}
In getView
int type= getItemViewType(i); // determine type using position.
switch (type) {
case TYPE_ITEM1:
view= mInflater.inflate(R.layout.post_header_layout, null); // inflate layout for header
break;
case TYPE_ITEM2:
view = mInflater.inflate(R.layout.post_text_layout, null); // inflate layout for quote
break;
case TYPE_ITEM3:
quote = mInflater.inflate(R.layout.post_quote_layout, null); // inflate layout for message
break;
....
You need to use a View Holder for smooth scrolling and performance.
http://developer.android.com/training/improving-layouts/smooth-scrolling.html
You can check the tutorial below
http://android.amberfog.com/?p=296
First of all you want to reuse convertView that has been passed as one of the argument. This way you can avoid inflating the item View.
Secondly, you could use something as ViewHolder to store references to your inner Views. Using ViewHolder will increase performance whether you are inflating view or finding them by id as both methods are very expensive.
Set the ViewHolder as a Tag on item View.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder viewHolder;
// if possible reuse view
if (convertView == null) {
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(resource, parent, false);
viewHolder = new ViewHolder(mInflater.inflate(R.layout.post_header_layout, null));
view.setTag(viewHolder);
} else {
// reuse view
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
//set text, listeners, icon, etc.
return view;
}
The ViewHolder is just private inner class storing referenced to view.
private static class ViewHolder {
private final View view;
private ViewHolder(View view) {
this.view = view;
}
}
Talk about ListView usage was given at Google IO 2010.
The inflater needs to know the real type of the futur parent ViewGroup, therefore the following code is erroneous:
view = mInflater.inflate(R.layout.forum_post,null);
and instead, you should use this one:
view = mInflater.inflate(R.layout.forum_post,viewGroup,false);
Same thing for the other inflate: use the real parent (view in this case) or another viewGroup which is of the same type as the (futur) parent; otherwise the LayoutParameters will not be set to the right type and the values that you have specified in your XML code will be lost (never used).

Categories

Resources