Skip to content Skip to sidebar Skip to footer

Custom Adapter To Make Listview With Different Items

What I want is to have a listview with different types of items in each row of the listview. I know that I need to use a custom adapter that extends BaseAdapter and not an ArrayAda

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:

public class MultiTypeAdapter extends BaseAdapter {

private LayoutInflater mInflater;
private Context mContext;
private List<IAdapterItem> mItems;

public enum RowType {
    ITEM_TYPE_ONE, ITEM_TYPE_TWO
}

/**
 * @param context
 * @param itemsList
 */
private MultiTypeAdapter(Context context, List<IAdapterItem> itemsList) {
    mItems = itemsList;
    mContext = context;
    mInflater = LayoutInflater.from(context);
}

@Override
public int getViewTypeCount() {
    return RowType.values().length;
}

@Override
public int getItemViewType(int position) {
    return getItem(position).getViewType().ordinal();
}

//View is generated by children
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    return getItem(position).getView(mInflater, convertView, mContext);
}

@Override
public boolean isEnabled(int position) {
    return getItem(position).isEnabled();
}

@Override
public long getItemId(int position) {
    return getItem(position).getItemId();
}

@Override
public IAdapterItem getItem(int position) {
    return mItems.get(position); 
}

...
}

Then you have child components that implement their own getView() method.

public class ItemTypeOne implements IAdapterItem {


@Override
public RowType getViewType() {
    return RowType.ITEM_TYPE_ONE;
}

@Override
public View getView(LayoutInflater inflater, View convertView, Context context) {
    View view = convertView;
        view = inflater.inflate(R.layout.item_type_one, null);
        // Set the view elements
        return 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"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="?android:attr/listPreferredItemHeight"
        android:padding="6dip">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="fill_parent">
            <TextView
                android:id="@+id/toptext"
                android:layout_width="fill_parent"
                android:layout_height="0dip"
                android:layout_weight="1"
                android:gravity="center_vertical"
            />
            <TextView
                android:layout_width="fill_parent"
                android:layout_height="0dip"
                android:layout_weight="1"
                android:id="@+id/bottomtext"
                android:singleLine="true"
                android:ellipsize="marquee"
            />
        </LinearLayout>

        <CheckBox
            android: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;

public class OurTasksArrayAdapter extends ArrayAdapter<Task> {

    private Context context;

    public OurTasksArrayAdapter(Context context, int textResourceId, ArrayList<Task> tasks) {
        super(context, textResourceId, tasks);
        this.context = context;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        if (view == null) {
            LayoutInflater layoutInflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = layoutInflater.inflate(R.layout.task_row, null);
        }
        Task task = getItem(position);
        if (task != null) {

            // CheckBox
            CheckBox cbIsTaskCompleted = (CheckBox) view.findViewById(R.id.cbIsTaskCompleted);
            cbIsTaskCompleted.setTag(position);
            cbIsTaskCompleted.setChecked(task.isTaskCompleted());
            cbIsTaskCompleted.setOnCheckedChangeListener(mListener);

            TextView tt = (TextView) view.findViewById(R.id.toptext);
            TextView bt = (TextView) view.findViewById(R.id.bottomtext);
            if (tt != null) {
                tt.setText("Name: " + task.getTaskDescription());
            }
            if (bt != null) {
                bt.setText("Status: " + task.getTaskDescription());
            }
        }

        GoalActivity ga = (GoalActivity) context;
        ga.updateTaskProgress();

        return view;
    }

    OnCheckedChangeListener mListener = new OnCheckedChangeListener() {
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
             GoalActivity ga = (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:

public class Adapter extends BaseAdapter{

private static final int VIEW_TYPE_COUNT = 2;
private static final int ITEM_1 = 0;
private static final int ITEM_2= 1;
private final int VIEWTYPES[] = {Item_1, ITEM_2};
private LayoutInflater mInflater;

public Adapter(Context context){
         // Cache the LayoutInflate to avoid asking for a new one each time.
         mInflater = LayoutInflater.from(context);

    }

@Override
        public int getItemViewType(int position) {
             return VIEWTYPES[mPostList.get(position).getViewType()];
        }

@Override
        public int getViewTypeCount(){
            return VIEW_TYPE_COUNT;
        }


@Override
        public 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;
            int type = getItemViewType(position);


            if (convertView == null) {
            holder = new ViewHolder();
            holder2 = new ViewHolder2();
                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;
}

}


static class ViewHolder {
  //Store layout1 views here
  TextView text1;
}

static class ViewHolder2{
  //Store layout2 views here
  TextView text2;

}

Post a Comment for "Custom Adapter To Make Listview With Different Items"