Custom Adapter To Make Listview With Different Items
Solution 1:
Your ArrayAdapter
implementation could have worked, but you needed to return the row View
you inflated in the getView()
method, instead of delegating to the super implementation.
Solution 2:
The reason you got this error is because ArrayAdapters require a Resource Id for a TextView that will exist in each item in the list. It will try to find a textview with this resource Id and then set it to some text based on what's in the ArrayAdapter. This however, is ignored if you override the getView()
method of the adapter.
To implement what you want, there are a few approaches. If you have reusable components in your list (e.g. You different types of items you show, but you may show the same type of item multiple times), then I suggest you do something like:
publicclassMultiTypeAdapterextendsBaseAdapter {
private LayoutInflater mInflater;
private Context mContext;
private List<IAdapterItem> mItems;
publicenumRowType {
ITEM_TYPE_ONE, ITEM_TYPE_TWO
}
/**
* @param context
* @param itemsList
*/privateMultiTypeAdapter(Context context, List<IAdapterItem> itemsList) {
mItems = itemsList;
mContext = context;
mInflater = LayoutInflater.from(context);
}
@OverridepublicintgetViewTypeCount() {
return RowType.values().length;
}
@OverridepublicintgetItemViewType(int position) {
return getItem(position).getViewType().ordinal();
}
//View is generated by children@Overridepublic View getView(int position, View convertView, ViewGroup parent) {
return getItem(position).getView(mInflater, convertView, mContext);
}
@OverridepublicbooleanisEnabled(int position) {
return getItem(position).isEnabled();
}
@OverridepubliclonggetItemId(int position) {
return getItem(position).getItemId();
}
@Overridepublic IAdapterItem getItem(int position) {
return mItems.get(position);
}
...
}
Then you have child components that implement their own getView()
method.
publicclassItemTypeOneimplements IAdapterItem {
@OverridepublicRowTypegetViewType() {
returnRowType.ITEM_TYPE_ONE;
}
@OverridepublicViewgetView(LayoutInflater inflater, View convertView, Context context) {
View view = convertView;
view = inflater.inflate(R.layout.item_type_one, null);
// Set the view elementsreturn view;
}
}
With this approach, you create a new class to implement IAdapterItem for each 'type' in your list. This approach is pretty clean as each child knows how to display itself properly. I wouldn't recommend this approach if you aren't using different types.
Solution 3:
corsair992 is right. When you return row
istead of super.getView... this could work. Just be careful when you do lists with different rows. The variable convertView will not work properly! For a row with TYPE_ITEM1 you can get a convertView of TYPE_ITEM2 and I suppose it will not look fine in your case :) You would have to check the type of convertView and when it's the one you want you can use it, otherwise you have to inflate agian.
Solution 4:
I'm not sure why you are getting the error you are. I may be able to help if you give me the code that initializes the adapter. But I have my custom adapter that contains two textviews and a checkbox. So it might be able to help.
Here is the xml row file...
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="?android:attr/listPreferredItemHeight"android:padding="6dip"><LinearLayoutandroid:orientation="vertical"android:layout_width="0dip"android:layout_weight="1"android:layout_height="fill_parent"><TextViewandroid:id="@+id/toptext"android:layout_width="fill_parent"android:layout_height="0dip"android:layout_weight="1"android:gravity="center_vertical"
/><TextViewandroid:layout_width="fill_parent"android:layout_height="0dip"android:layout_weight="1"android:id="@+id/bottomtext"android:singleLine="true"android:ellipsize="marquee"
/></LinearLayout><CheckBoxandroid:id="@+id/cbIsTaskCompleted"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:focusable="false"/></LinearLayout>
Custom adapter file...
package com.isaac.jeff;
import java.util.ArrayList;
import com.isaac.jeff.screen.GoalActivity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
publicclassOurTasksArrayAdapterextendsArrayAdapter<Task> {
private Context context;
publicOurTasksArrayAdapter(Context context, int textResourceId, ArrayList<Task> tasks) {
super(context, textResourceId, tasks);
this.context = context;
}
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {
Viewview= convertView;
if (view == null) {
LayoutInflaterlayoutInflater= (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.task_row, null);
}
Tasktask= getItem(position);
if (task != null) {
// CheckBoxCheckBoxcbIsTaskCompleted= (CheckBox) view.findViewById(R.id.cbIsTaskCompleted);
cbIsTaskCompleted.setTag(position);
cbIsTaskCompleted.setChecked(task.isTaskCompleted());
cbIsTaskCompleted.setOnCheckedChangeListener(mListener);
TextViewtt= (TextView) view.findViewById(R.id.toptext);
TextViewbt= (TextView) view.findViewById(R.id.bottomtext);
if (tt != null) {
tt.setText("Name: " + task.getTaskDescription());
}
if (bt != null) {
bt.setText("Status: " + task.getTaskDescription());
}
}
GoalActivityga= (GoalActivity) context;
ga.updateTaskProgress();
return view;
}
OnCheckedChangeListenermListener=newOnCheckedChangeListener() {
publicvoidonCheckedChanged(CompoundButton buttonView, boolean isChecked) {
GoalActivityga= (GoalActivity) context;
getItem((Integer)buttonView.getTag()).setTaskCompleted(isChecked); // get the tag so we know the row and store the status
ga.updateTaskProgress();
//notifyDataSetChanged();
}
};
}
Hope this helps!
Solution 5:
This is how i have done ListView with 2 different layout:
publicclassAdapterextendsBaseAdapter{
privatestaticfinalintVIEW_TYPE_COUNT=2;
privatestaticfinalintITEM_1=0;
privatestaticfinalint ITEM_2= 1;
privatefinalint VIEWTYPES[] = {Item_1, ITEM_2};
private LayoutInflater mInflater;
publicAdapter(Context context){
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
}
@OverridepublicintgetItemViewType(int position) {
return VIEWTYPES[mPostList.get(position).getViewType()];
}
@OverridepublicintgetViewTypeCount(){
return VIEW_TYPE_COUNT;
}
@Overridepublic View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unneccessary calls// to findViewById() on each row.
ViewHolder holder;
ViewHolder2 holder2;
inttype= getItemViewType(position);
if (convertView == null) {
holder = newViewHolder();
holder2 = newViewHolder2();
switch(type){
case ITEM_1:
convertView = mInflater.inflate(R.layout.ITEM_1_LAYOUT, null);
holder.text1 = (TextView)convertView.findViewById();
convertView.setTag(R.layout.ITEM_1_LAYOUT, holder);
break;
case ITEM_2:
convertView = mInflater.inflate(R.layout.iTEM_2_LAYOUT, null);
holder2.text2 = (TextView)convertView.findViewById();
convertView.setTag(R.layout.ITEM_2_LAYOUT, holder2);
break;
}
} else{
// Get the ViewHolder back to get fast access to the TextViews
holder = (ViewHolder) convertView.getTag(R.layout.ITEM_1_LAYOUT);
holder2 = (ViewHolder2)convertView.getTag(R.layout.ITEM_2_LAYOUT);
}
switch(type){
case ITEM_1:
holder.text1.setText("1");
break;
case ITEM_2:
holder.text2.setText("2");
break;
}
return convertView;
}
}
staticclassViewHolder {
//Store layout1 views here
TextView text1;
}
staticclassViewHolder2{
//Store layout2 views here
TextView text2;
}
Post a Comment for "Custom Adapter To Make Listview With Different Items"