【问题标题】:Displaying different type of rows in an Android list在 Android 列表中显示不同类型的行
【发布时间】:2013-06-17 16:10:42
【问题描述】:

我有一个多态实体列表,例如List<Person>,其中一个人可以是雇员、经理、士兵、皇室成员等...我想在一个 android 列表视图中显示人员列表,其中每种类型的人有不同的行模板和略有不同的数据。

显示不同类型的不同行的正确方法是什么?

两个不好的(?)解决方案:

  1. Person类里面放一个抽象的getView方法,这样每个不同的人都会通过多态创建正确的视图。 --> 这将混合模型和 MVC 的视图 - 即。如果我想在不同的屏幕(例如表格视图)中显示列表,那么它会中断。

  2. 将模型到视图的逻辑放在适配器中(继承自 ArrayAdapter<Person>)。例如在getView 中,我可以检查此人的getClass() 并相应地填充正确的视图。 --> 这个方法最终会得到一长串 if-else 语句,每个人类型一个,并且在添加新类型的人时需要扩展——从面向对象的角度来看,这通常是一种糟糕代码的味道。这是“How to create list with different elements and actions?”中建议的解决方案

有比上述(2)更好的解决方案吗?

【问题讨论】:

  • 这是所有Android UI设计中最头疼的问题之一。我很乐意看到更多的 Android 专家参与进来。

标签: android model-view-controller android-listview android-arrayadapter


【解决方案1】:

我个人会选择类似于您的第二个解决方案的东西。我可能会在Person 类中包含一个抽象方法来识别人的类型,因此您可以使用它而不是在Person 调用中检查Person 对象上的getClass()

在您的自定义适配器中,扩展 BaseAdapter 并确保 getViewTypeCount() 返回您在数据集中拥有的不同类型人员的数量,并且确保 getItemViewType(int position) 返回数据集中位置的正确标识符。

这个问题有很多关于这个主题的有用信息:

getViewTypeCount and getItemViewType methods of ArrayAdapter

【讨论】:

  • 好的,所以 3 个答案建议相同的解决方案 - 我想没有更好的方法。我选择你的答案主要是为了最快,也是为了给我指出 getViewTypeCount 和 getItemViewType 的解释。
  • 这实际上不是一个坏方法。就像我说的,你可以在你的 Person 类中创建一个抽象方法,它也可以在 getItemViewType() 方法中使用。此外,请查看 ViewHolder 模式 - 它可以进一步提高您的性能。
  • 这不是一个糟糕的解决方案,但它很糟糕。添加/删除类型需要更改 3 个函数,并且 getItemViewTypegetView 不同步将在运行时而不是编译时发现。我想象一个解决方案,其中添加对新类型行的支持只是将一个新类放入项目中,并且可能添加一行代码将其连接到适配器。
  • 编辑:你是对的,为 getItemViewType 添加一个抽象方法将消除与 getView 不同步的风险,并将消除为新类型编辑该函数的必要性,所以我列出了缺点有点静音。
【解决方案2】:

创建您自己的 ListAdapter,它像这样从 BaseAdapter 扩展

public class YourListAdapter extends BaseAdapter implements Filterable {
...
}

覆盖 getViewTypeCount() 和 getItemViewType()

@Override
public int getViewTypeCount() {
    return 2;//count of types
}

@Override
public int getItemViewType(int position) {
    return YourPersonList.get(position).getMyViewType();
}

在getView(..)中

int type = getItemViewType(position);
switch(type){
case 0:
 //set the view to your layout
break;
case 1:
 //set the view to another layout
break;
}

或多或少是这样的……

//编辑:查看来自 michell https://stackoverflow.com/a/17152430/1847899 的帖子

【讨论】:

    【解决方案3】:

    您可以在适配器中覆盖两种方法,使这更容易。它们是:

    @Override
    public int getViewTypeCount(){
      return viewTypeCount;
    }
    
    @Override
    public int getItemViewType(int pos){
      if (getItem(pos).type == employee)
        return VIEW_TYPE_EMPLOYEE;
      else if (getItem(pos).type == manager)
        return VIEW_TYPE_MANAGER;
    }
    

    使用上面的方法,你还是需要做一些工作,比如当视图需要膨胀时,你可能需要从getView内部调用getItemViewType(position),但是当你得到一个已经被回收的视图时,适配器应该根据行位置为您提供正确的类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-15
      • 1970-01-01
      • 2015-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多