如何在运行时向ListView项添加动态视图?

Cha*_*han 8 user-interface android listview listadapter

我的问题是我不知道是否应该使用多个列表视图或可以动态增长的自定义列表视图项适配器.例如,对于特定用户,他们可以进行多项活动:
- 拍照
- 说些什么
- 签到
- ......

显然,这个列表可以随着用户完成更多活动而增长.大多数时候,我经常创建一个自定义项适配器,它从BaseAdapter以下ItemHolder模式扩展并使用模式:

public class PlaceItemAdapter extends BaseAdapter {
    private Activity        context;
    private List<Place>     places;
    private boolean         notifyChanged = false;

    public PlaceItemAdapter(Activity context, List<Place> places) {
        super();
        this.context = context;
        this.places = places;
    }

    public int getCount() {
        return places.size();
    }

    public Object getItem(int position) {
        return places.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public static class ItemViewHolder {
        TextView nameTextView;
        TextView typesTextView;
        TextView ratingTextView;
        ImageView mapIconImageView;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ItemViewHolder holder;
        LayoutInflater inflater = context.getLayoutInflater();
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.place_item, null);
            holder = new ItemViewHolder();
            holder.nameTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_name);
            holder.typesTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_address);
            holder.ratingTextView = (TextView) convertView.findViewById(R.id.place_item_xml_textview_rating);
            holder.mapIconImageView = (ImageView) convertView.findViewById(R.id.place_item_xml_imageview_location_icon);

            convertView.setTag(holder);
        }
        else {
            holder = (ItemViewHolder) convertView.getTag();
        }

        holder.nameTextView.setText(places.get(position).getName());
        holder.typesTextView.setText(places.get(position).getAddress());
        holder.ratingTextView.setText(Integer.toString(places.get(position).getRating()));
        /*
         * This task is time consuming!
         * TODO: find a workaround to handle the image
         */
        // holder.mapIconImageView.setImageBitmap(DownloadImageHelper.downloadImage(places.get(position).getIconUrl()));
        holder.mapIconImageView.setImageResource(R.drawable.adium);
        return convertView;
    }

    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
        notifyChanged = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此方法,GUI小部件的数量是固定的,这意味着我无法使我的listview项看起来如下图所示.

    public static class ItemViewHolder {
        TextView nameTextView;
        TextView typesTextView;
        TextView ratingTextView;
        ImageView mapIconImageView;
    }
Run Code Online (Sandbox Code Playgroud)

我最初的方法是创建一个嵌套在适配器项内的动态视图,但它会产生重复的视图.为了避免重复查看,我设置convertView为null,这意味着每次加载时,它都会创建一个新的ItemViewHolder,最终会占用我所有的内存.:(那么我怎么能处理这种情况?一个极小的工作示例将不胜感激.

重复视图

public class FriendFeedItemAdapter extends BaseAdapter {
    private List<FriendFeedItem> items;
    private Activity context;
    private static LayoutInflater inflater;
    public ImageLoader imageLoader;
    private ItemViewHolder viewHolder;

    public FriendFeedItemAdapter(Activity context, List<FriendFeedItem> items) {
        this.context = context;
        this.items = items;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        imageLoader = new ImageLoader(context.getApplicationContext());
    }

    public int getCount() {
        return items.size();
    }

    public Object getItem(int position) {
        return items.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public static class ItemViewHolder {
        TableLayout  table;
        ImageView imageViewUserPicture;
        TextView textViewUsername;
        TextView textViewWhatUserDo;
        TextView textViewWhere;
        TextView textViewTime;
        ImageView imageViewSnapPictureBox;
        TextView textViewWriteOnWallMessageBox;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.friend_list_feed_item, null);
            viewHolder = new ItemViewHolder();
            viewHolder.table = (TableLayout) convertView.findViewById(R.id.friend_list_feed_item_xml_tablelayout_table);
            viewHolder.imageViewUserPicture = (ImageView) convertView.findViewById(R.id.friend_list_feed_item_xml_imageview_user_picture);
            viewHolder.textViewUsername = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_username);
            viewHolder.textViewWhatUserDo = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_what_user_do);
            viewHolder.textViewWhere = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_where);
            viewHolder.textViewTime = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_at_what_time);

            convertView.setTag(viewHolder);
        }
        else {
            viewHolder = (ItemViewHolder) convertView.getTag();
        }

        imageLoader.displayImage(items.get(position).getFriendPictureUrl(), viewHolder.imageViewUserPicture);
        viewHolder.textViewUsername.setText(items.get(position).getFriendName());
        viewHolder.textViewWhere.setText("at " + items.get(position).getPlaceName());
        viewHolder.textViewTime.setText("@" + items.get(position).getActivityTime());

        if (items.get(position).getChallengeType() == Challenge.Type.CHECK_IN) {
            viewHolder.textViewWhatUserDo.setText("has checked in.");
        }
        else if (items.get(position).getChallengeType() == Challenge.Type.SNAP_PICTURE) {
            viewHolder.textViewWhatUserDo.setText("has snap a picture.");
            // add picture box
            View rowView = inflater.inflate(R.layout.snap_picture_row_item, null);
            viewHolder.imageViewSnapPictureBox = (ImageView) rowView.findViewById(R.id.snap_picture_row_item_xml_imageview_picture);
            imageLoader.displayImage(items.get(position).getActivitySnapPictureUrl(), viewHolder.imageViewSnapPictureBox);
            viewHolder.table.addView(rowView);
        }
        else if (items.get(position).getChallengeType() == Challenge.Type.WRITE_ON_WALL) {
            viewHolder.textViewWhatUserDo.setText("has written a message on wall.");
            // add message box
            View rowView = inflater.inflate(R.layout.write_on_wall_row_item, null);
            viewHolder.textViewWriteOnWallMessageBox = (TextView) rowView.findViewById(R.id.write_on_wall_row_item_xml_textview_wall_message);
            viewHolder.textViewWriteOnWallMessageBox.setText(items.get(position).getActivityComment());
            viewHolder.table.addView(rowView);
        }
        else if (items.get(position).getChallengeType() == Challenge.Type.QUESTION_ANSWER) {
            viewHolder.textViewWhatUserDo.setText("has answered a question.");
        }
        else { // Challenge.Type.OTHER
            viewHolder.textViewWhatUserDo.setText("has done some other challenges.");
        }

        return convertView;
    }
}
Run Code Online (Sandbox Code Playgroud)

广泛的内存使用

public View getView(int position, View convertView, ViewGroup parent) {
        ItemViewHolder holder = null;
        LayoutInflater inflater = context.getLayoutInflater();

        convertView = inflater.inflate(R.layout.friend_list_feed_item, null);
        // create holder
        holder = new ItemViewHolder();
        // default field
        holder.table = (TableLayout) convertView.findViewById(R.id.friend_list_feed_item_xml_tablelayout_table);
        holder.imageViewUserPicture = (ImageView) convertView.findViewById(R.id.friend_list_feed_item_xml_imageview_user_picture);
        holder.textViewUsername = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_username);
        holder.textViewWhatUserDo = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_what_user_do);
        holder.textViewWhere = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_where);
        holder.textViewTime = (TextView) convertView.findViewById(R.id.friend_list_feed_item_xml_textview_at_what_time);
        convertView.setTag(holder);

        holder.imageViewUserPicture.setImageURI(items.get(position).getFriendPictureUri());
        holder.textViewUsername.setText(items.get(position).getFriendName());
        holder.textViewWhere.setText("at " + items.get(position).getPlaceName());
        holder.textViewTime.setText("@" + items.get(position).getActivityTime());

        if (items.get(position).getChallengeType() == Challenge.Type.CHECK_IN) {
            holder.textViewWhatUserDo.setText("has checked in.");
        }
        else if (items.get(position).getChallengeType() == Challenge.Type.SNAP_PICTURE) {
            holder.textViewWhatUserDo.setText("has snap a picture.");
            // add picture box
            View rowView = inflater.inflate(R.layout.snap_picture_row_item, null);
            holder.imageViewSnapPictureBox = (ImageView) rowView.findViewById(R.id.snap_picture_row_item_xml_imageview_picture);
            holder.imageViewSnapPictureBox.setImageURI(items.get(position).getActivitySnapPictureUri());
            holder.table.addView(rowView);
        }
        else if (items.get(position).getChallengeType() == Challenge.Type.WRITE_ON_WALL) {
            holder.textViewWhatUserDo.setText("has written a message on wall.");
            // add message box
            View rowView = inflater.inflate(R.layout.write_on_wall_row_item, null);
            holder.textViewWriteOnWallMessageBox = (TextView) rowView.findViewById(R.id.write_on_wall_row_item_xml_textview_wall_message);
            holder.textViewWriteOnWallMessageBox.setText(items.get(position).getActivityComment());
            holder.table.addView(rowView);
        }
        else if (items.get(position).getChallengeType() == Challenge.Type.QUESTION_ANSWER) {
            holder.textViewWhatUserDo.setText("has answered a question.");
        }
        else { // Challenge.Type.OTHER
            holder.textViewWhatUserDo.setText("has done some other challenges.");
        }

        return convertView;
    }
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在此输入图像描述

Jin*_*n35 9

如果您有少量可能的变体(在截图中我可以看到2个不同的列表项)您有两种可能的变体:

  1. 通过方法设置不同类型的计数,并为每个项目提供类型 - 您可以使用convertView.

  2. 创建"完整"列表项视图并设置元素的可见性,您不希望在特定项目中看到这些元素.

#2的一些代码:

public class ListTestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    List<Element> list = new ArrayList<Element>();
    list.add(new Element(0));
    list.add(new Element(0));
    list.add(new Element(1));
    list.add(new Element(0));
    list.add(new Element(1));
    list.add(new Element(1));
    list.add(new Element(0));
    list.add(new Element(0));
    list.add(new Element(1));
    list.add(new Element(1));
    list.add(new Element(1));
    list.add(new Element(0));
    list.add(new Element(0));
    list.add(new Element(1));
    list.add(new Element(0));
    list.add(new Element(0));
    ((ListView) findViewById(android.R.id.list)).setAdapter(new SampleAdapter(this, list));
}

private class SampleAdapter extends BaseAdapter {

    private List<Element> list;
    private Context context;

    public SampleAdapter(Context context, List<Element> list) {
        this.list = list;
        this.context = context;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Element getItem(int position) {
        return list.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null)
            switch (getItemViewType(position)) {
            case 0:
                convertView = new CheckBox(context);
                break;
            default:
                convertView = new Button(context);
                break;
            }
        // Output here shows that you can lay on getItemViewType(position) as indicator of convertView type or structure
        Log.e("test", getItemViewType(position) + ": " + convertView.getClass().getSimpleName());
        return convertView;
    }

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

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

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

private class Element {
    public int type;

    public Element(int type) {
        this.type = type;
    }
}
}
Run Code Online (Sandbox Code Playgroud)