2010-08-18 88 views
46

对于不同的项目,我有一个具有不同布局的ListView。有些项目是分隔符。有些项目是不同的,因为他们拥有不同种类的数据等。为具有不同项目布局的ListView创建ViewHolders

我想实现ViewHolders以加快getView过程,但我不太清楚如何去做。不同的布局具有不同的数据片段(这使得命名困难)以及我想要使用的不同数量的视图。

我应该如何去这样做呢?

我可以想出的最好的办法是用X条目创建一个通用的ViewHolder,其中X是项目布局中具有最高数目的视图数量。对于包含少量视图的其他视图,我只需在ViewHolder中使用这些变量的一小部分。所以说我有2个布局我用于2个不同的项目。一个有3个TextViews,另一个有1个。我将创建一个包含3个TextView变量的ViewHolder,并仅将其中的1个用于其他项目。我的问题是,这可能会变得非常丑陋,感觉真的很难受;尤其是当项目布局可能有许多不同类型的许多视图时。

这是一个非常基本的getView:

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 

    MyHolder holder; 

    View v = convertView; 
    if (v == null) { 
     LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     v = vi.inflate(R.layout.layout_mylistlist_item, parent, false); 

     holder = new MyHolder(); 
     holder.text = (TextView) v.findViewById(R.id.mylist_itemname); 
     v.setTag(holder); 
    } 
    else { 
     holder = (MyHolder)v.getTag(); 
    } 

    MyListItem myItem = m_items.get(position); 

    // set up the list item 
    if (myItem != null) { 
     // set item text 
     if (holder.text != null) { 
      holder.text.setText(myItem.getItemName()); 
     } 
    } 

    // return the created view 
    return v; 
} 

假设我有不同类型的行布局,我可以为每种类型行的ViewHolder。但是,我会声明“持有人”是什么类型?或者我会为每种类型声明一个持有者,然后将其用于我所在行的类型。

回答

105

ListView有一个内置的类型管理系统。在您的适配器中,您有几种类型的项目,每种都有自己的视图和布局。通过重写getItemViewType来返回给定位置的数据类型,ListView可以保证为该类型的数据传入正确的convertview。然后,在你的getView方法中,简单地检查数据类型并使用switch语句以不同的方式处理每种类型。

每个布局类型都应该有自己的视图,以便命名清晰并易于维护。将ViewHolders命名为与每种数据类型相关的内容,以保持一切正常。

尝试将所有内容重叠到一个ViewHolder中是不值得的。

编辑

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    int viewType = this.getItemViewType(position); 

    switch(viewType) 
    { 
     case TYPE1: 

     Type1Holder holder1; 

     View v = convertView; 
     if (v == null) { 
      LayoutInflater vi = (LayoutInflater)getContext().getSystemService  (Context.LAYOUT_INFLATER_SERVICE); 
      v = vi.inflate(R.layout.layout_mylistlist_item_type_1, parent, false); 

      holder1 = new Type1Holder(); 
      holder1.text = (TextView) v.findViewById(R.id.mylist_itemname); 
      v.setTag(holder1); 
     } 
     else { 
      holder1 = (Type1Holder)v.getTag(); 
     } 

     MyListItem myItem = m_items.get(position); 

     // set up the list item 
     if (myItem != null) { 
      // set item text 
      if (holder1.text != null) { 
       holder1.text.setText(myItem.getItemName()); 
      } 
     } 

     // return the created view 
     return v; 


    case TYPE2: 
      Type2Holder holder2; 

     View v = convertView; 
     if (v == null) { 
      LayoutInflater vi = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      v = vi.inflate(R.layout.layout_mylistlist_item_type_2, parent, false); 

      holder2 = new Type2Holder(); 
      holder2.text = (TextView) v.findViewById(R.id.mylist_itemname); 
      holder2.icon = (ImageView) v.findViewById(R.id.mylist_itemicon); 
      v.setTag(holder1); 
     } 
     else { 
      holder2 = (Type2Holder)v.getTag(); 
     } 

     MyListItem myItem = m_items.get(position); 

     // set up the list item 
     if (myItem != null) { 
      // set item text 
      if (holder2.text != null) { 
       holder2.text.setText(myItem.getItemName()); 
      } 

      if(holder2.icon != null) 
       holder2.icon.setDrawable(R.drawable.icon1); 
     } 


     // return the created view 
     return v; 


     default: 
      //Throw exception, unknown data type 
    } 
} 
+0

也许我需要一些刷了我的Java的那么。在我的ListActivities的getView函数的开始,我实例化了我为ListView定义的持有者。然后我检查convertView为空和getTag或创建持有人并设置项目。如果我要为物品类型使用不同的持有者,那么我应该如何在getView开始时声明持有者?或者是否需要为我的所有项目类型实例化1并初始化并使用与该行类型相对应的那个? – Andrew 2010-08-18 18:34:59

+0

请看我编辑的帖子顶部 – Andrew 2010-08-18 18:39:42

+0

@Andrew,每个持有人将在个案陈述之一中单独定义。将所有现有代码放入ecah case语句中,但更改每个代码的查看者类型和数据处理。我会用一个例子来编辑我的答案。 – CodeFusionMobile 2010-08-18 18:45:44

0

又如。

公共类CardArrayAdapter扩展ArrayAdapter {

public CardArrayAdapter(Context context) { 
    super(context, R.layout.adapter_card); 
} 

@Override 
public View getView(int position, View view, ViewGroup parent) { 

    final Card card = getItem(position); 
    ViewHolder holder; 

    //if (view != null) { 
     //holder = (ViewHolder) view.getTag(); 
    //} else { 
    Log.d("card.important?", card.name + " = " + Boolean.toString(card.important)); 
    if(card.important) { 
     view = LayoutInflater.from(getContext()).inflate(R.layout.adapter_card_important, parent, false); 
    }else { 
     view = LayoutInflater.from(getContext()).inflate(R.layout.adapter_card, parent, false); 
    } 
    holder = new ViewHolder(view); 
    view.setTag(holder); 
    //} 

    // IMG 
    Picasso.with(getContext()) 
      .load(card.logo) 
      .placeholder(R.drawable.ic_phonebook) 
      .error(R.drawable.ic_phonebook) 
      .fit() 
      .centerCrop() 
      .transform(new CircleTransform()) 
      .into(holder.logo); 

    holder.name.setText(card.name); 

    if(card.important) { 
     holder.category.setVisibility(View.VISIBLE); 
     if (card.category.equals("airline")) { 
      card.category = "airlines"; 
     } 
     int id = getContext().getResources().getIdentifier(card.category, "string", getContext().getPackageName()); 
     holder.category.setText(getContext().getResources().getString(id)); 
    }else { 
     holder.category.setVisibility(View.GONE); 
    } 

    holder.tagline.setText(card.tagline); 
    holder.favorite.setChecked(card.favorite); 

    holder.favorite.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      card.favorite = ((CheckBox) v).isChecked(); 
      card.save(); 
     } 
    }); 

    return view; 

} 

static class ViewHolder { 
    @InjectView(R.id.logo) ImageView logo; 
    @InjectView(R.id.name) TextView name; 
    @InjectView(R.id.category) TextView category; 
    @InjectView(R.id.tagline) TextView tagline; 
    @InjectView(R.id.favorite) CheckBox favorite; 
    public ViewHolder(View view) { 
     ButterKnife.inject(this, view); 
    } 
} 

}

+0

我认为,这会起作用,但它使viewholder不太可用,因为每次它改变类型,你膨胀新的布局 – hakim 2016-03-30 02:45:57

相关问题