为选定列表项提供自定义视图的最佳方式

Best way to provide custom view for selected list item

目标:考虑到一次只能选择一个项目,对所选项目进行完全自定义布局。

我不想让 getViewTypeCount/getItemViewType 参与选择,因为它们已在此适配器中用于不同目的。

一个明显的选择是膨胀自定义布局以通过将适配器修改为类似以下内容来指示所选项目:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
         ViewHolder holder;
         ... 
         // initialize convertView, holder, regular stuff

         // Now, the questionable part:

        if (position == mSelectedPosition) {
           // use custom layout to indicate highlight/selection
           convertView = inflater.inflate(R.layout.custom_selection_layout, parent, false);
        } else {
            // clear up selection 
            // also convertView could be recycled view and be of unexpected type 
        }
    }

在性能方面应该不会太差,因为只有一个项目是 selected/inflated,但问题是 convertedView 可以是两种不同的类型,额外的 cast/checks是需要的。
这种做法是不是不受欢迎?

另一种选择是:根据 if (position == mSelectedPosition) 条件,将 selected/unselected 版本的布局合并到 item_layout 中,其中一个 hidden/shown 在适配器中动态组合。 这是个好主意吗?

最终,正确的方法是什么?

谢谢

我会选择第一种方法。您的自定义布局应仅应用于整个列表中的一个视图,因此您唯一需要做的就是避免回收此类视图。我正在使用这种方法在列表中的特定点加载分隔符,我没有发现任何性能问题。

另一方面,让我们这么说吧——将布局合二为一并更改可见性对我来说似乎不是最佳选择,因为您的视图持有者会变得相当大(您需要携带 all 里面的视图,我猜)为了整个列表中只有一个 child 的好处。所有回收的 non-selected 视图每次都会面临位置检查,这对于大多数(除了一个)情况都是不必要的。


至于在视图被回收后识别视图,一种可能的方法是也使用标签。

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

    if (position == mSelectedPosition) {
       convertView = inflater.inflate(R.layout.custom_selection_layout, parent, false);
       //here you upload convertView without the ViewHolder pattern, by using findViewById();
       //it's legit IMO because it gets called just once for the whole list.
       convertView.setTag("SELECTED_VIEW");
       return convertView;
    }

     ViewHolder holder;
     if (convertView == null || convertView.getTag("SELECTED_VIEW")) {
         //this convertView is not good. We inflate the regular layout
         convertView = inflater.inflate( ... );
     }

     //regular stuff
     ...
}