2011-12-27 18 views
6

Sorunum, birden çok liste görünümünü veya dinamik olarak büyüyebilen özel bir liste görüntüleme öğesi bağdaştırıcısı kullanmam gerekip gerekmediğimi bilmem. Örneğin, belirli bir kullanıcı için, birden çok etkin olabilir:
- Bir resim
çekin - Bir şey söyle
-
içinde kontrolü - ...Çalışma zamanında bir ListView öğesine dinamik görünüm nasıl eklenir?

Görünüşe göre, bu liste can kullanıcının sahip büyüdükçe olarak daha fazla aktivite yaptı. aşağıdaki gibi Çoğu zaman, sık sık ItemHolder desen BaseAdapter uzanan özel bir madde adaptörü oluşturma ve kullanma:

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; 
    } 
} 

Bu yöntemi kullanarak, numara GUI widget benim liste görünümü yapamaz yani sabittir öğe aşağıdaki resme benziyor. Benim ilk yaklaşma

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

ancak yinelenen görünümler üretecek, bir adaptör öğenin içine yuvalanmış bir dinamik görünüm yaratmaktı. Yinelenen görünümden kaçınmak için, convertView değerini null değerine ayarlıyorum. Bu, her yüklendiğinde yeni bir ItemViewHolder oluşturacak ve sonunda tüm belleğimi yiyor. :(Peki nasıl bu durumun üstesinden olabilir? Bir asgari çalışma örneği büyük takdir.

Yinelenen Görünüm

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; 
    } 
} 

Kapsamlı Bellek Kullanımı

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; 
    } 

enter image description here

enter image description here

cevap

9

İki olası varyantlar var (Ekran görüntüleri ben 2 farklı liste öğeleri görebilir): this yöntemle farklı türde

  1. Kur sayımı ve için type sağlamak her öğe - ve convertView kullanabilirsiniz.

  2. "Tam" liste öğesi görünümü oluştur ve özellikle öğede görmek istemediğiniz öğeler için görünürlüğü ayarlayın.

2. için bazı kod: Burada

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; 
    } 
} 
} 
+0

Yöntem 1'iniz için minimal bir çalışma örneği verebilir misiniz? – Chan

+0

benim düzenlenmiş cevabımı gör – Jin35

+0

Bu şekilde gidiyor. Görünümü oluşturmak için yöntemler sağlayan bir itemViewType 'kullanmayı tercih ediyorum (eğer convertView is null' ise) ve veriye bağlanma verilerini. Uygulama sınıfı, özgül 'ViewHolder'ı iç sınıf olarak beyan eder. Arabirimi bağdaştırıcınızın 'getItemViewType' – Oderik

2

Özel bir bağdaştırıcı sorununuzu çözer. Bunun nedeni, ListView'de her bir satıra eklenen görünümleri değiştirebilmenizdir, çünkü içeriği özel bağdaştırıcıda uyguladığınız mantık yoluyla değiştirebilirsiniz.

getView() yöntemi null olmayan bir görünüm döndürdüğünde, bu belirli satır için orada olan bir görünüm vardır. Bu durumda, söz konusu örnekte içeriği değiştirmek isteyebilirsiniz veya istemeyebilirsiniz. Ya da o sıra için dinamik içerikli yepyeni bir görünüm oluşturabilirsiniz.

Dikkat edilmesi gereken bir nokta, getView() öğesinin adaptörünüzde bulunan öğeler kadar defa çağrılmasıdır. Eğer mümkün varyantların az sayıda varsa

1

muhtemelen adaptörü bunu her zaman değiştirmek zorunda kalmadan istediğiniz kadar öğe türlerini tanıtmak için izin edeceğiz bir fikir:

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    AbstractItem abstractItem = ((AbstractItem)getItem(position)); 
    // if null or new item type is different than the one already there 
    if (convertView == null || (convertView.getTag() != null 
      && ((AbstractItem)convertView.getTag()).getType().equals(abstractItem.getType())) { 
      convertView = abstractItem.inflateSelf(getContext()); 
    } 

    abstractItem.fillViewWithData(convertView); 
    convertView.setTag(abstractItem); 
    return convertView; 
} 

public class AbstractItem { 
    public abstract View inflateSelf(Context context); 
    public abstract String getType(); 
    public abstract void fillViewWithData(View view); 
} 

public class PictureSnapItem extends AbstractItem { 
    // data fields 
    WeakReference<Bitmap> wBitmap; 
    String pictureComment; 
    ... 

    public abstract View inflateSelf(Context context) { 
     // get layout inflater, inflate a layout resource, return 
     return ((Activity)context).getLayoutInflater.inflate(R.layout.picture_snap_item); 
    } 
    public abstract String getType() { 
     // return something class-specific, like this 
     return getClass().getCanonicalName(); 
    } 
    public abstract void fillViewWithData(View view) { 
     // fill the view with data from fields, assuming view has been 
     // inflated by this very class's inflateSelf(), maybe throw exception if 
     // required views can't be found 
     ImageView img = (ImageView) view.findViewById(R.id.picture); 
     TextView comment = (TextView) view.findViewById(R.id.picture_comment) 
    } 
} 

... ve daha sonra, AbstractItem'i genişletip, daha sonra getView() için herhangi bir ekleme varsa, herhangi bir eklemeye gerek yoktur.

İlgili konular