43

我在自定义 ArrayAdapter 中有一个 ListView,它在每一行中显示一个图标 ImageView 和一个 TextView。当我使列表足够长以让您滚动浏览它时,顺序开始正确,但是当我开始向下滚动时,一些较早的条目开始重新出现。如果我向上滚动,旧的顺序会改变。重复执行此操作最终会导致整个列表顺序看似随机。所以滚动列表要么导致子顺序发生变化,要么绘图没有正确刷新。

什么可能导致这样的事情发生?我需要将项目显示给用户的顺序与它们添加到 ArrayList 的顺序相同,或者至少保持一个静态顺序。如果我需要提供更详细的信息,请告诉我。任何帮助表示赞赏。谢谢。

4

4 回答 4

60

我遇到了类似的问题,但是当单击自定义列表中的项目时,屏幕上的项目会按顺序反转。如果我再次单击,它们会返回到原来的位置。

读完这篇文章后,我检查了我重载 getView 方法的代码。我从convertedView 中获取视图,如果它为空,那么我将在那时构建我的东西。但是,在放置断点后,我发现它在每次单击时调用此方法,并且在随后的单击中,convertedView 不为空,因此未设置项目。

这是一个例子:


public View getView(int position, View convertView, ViewGroup parent)
{
    View view = convertView;
    if (view == null)
    {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = vi.inflate(R.layout.listitemrow, null);

        RssItem rssItem = (RssItem) super.getItem(position);
        if (rssItem != null)
        {
            TextView title = (TextView) view.findViewById(R.id.rowtitle);
            if (title != null)
            {
                title.setText(rssItem.getTitle());
            }
        }
    }
    return view;
}

微妙的变化是将视图上空检查的右括号移动到膨胀之后:


public View getView(int position, View convertView, ViewGroup parent)
{
    View view = convertView;
    if (view == null)
    {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = vi.inflate(R.layout.listitemrow, null);
    }
    RssItem rssItem = (RssItem) super.getItem(position);
    if (rssItem != null)
    {
        TextView title = (TextView) view.findViewById(R.id.rowtitle);
        if (title != null)
        {
            title.setText(rssItem.getTitle());
        }
    }
    return view;
}

我希望这可以帮助遇到同样问题的其他人。

于 2010-10-06T16:15:52.323 回答
4

为了以更一般的方式进一步澄清下面farcats的答案,这是我的解释:

vi.inflate操作(此处需要从 XML 解析行的布局并创建适当的 View 对象)由if (view == null)语句包装以提高效率,因此不会发生同一对象的膨胀每次出现时都会一次又一次地出现。

但是,getView 方法的其他部分用于设置其他参数,因此不应包含在if (view == null)语句中。

类似地,在此方法的其他常见实现中,一些 textView、ImageView 或 ImageButton 元素需要使用 list[position] 中的值填充,使用findViewById和之后的.setText.setImageBitmap操作。这些操作必须在通过膨胀从头开始创建视图获取现有视图(如果不为空)之后进行。

另一个将此解决方案应用于 BaseAdapter 的好示例出现在BaseAdapter 中,导致 ListView 在滚动时出现故障

于 2012-01-10T18:56:38.867 回答
3

ListView 在您滚动时重用视图对象。您是否覆盖了 getView 方法?您需要确保为每个视图设置每个属性,不要假设它会记住您之前拥有的内容。如果您发布该方法,有人可能会指出您不正确的部分。

于 2010-06-02T05:43:28.913 回答
1

我有一个 ListView、AdapterView 和一个包含 EditText 和 3 个 Spinner 的视图(search_options)。ListView 项目是 (search_options) 布局的多个副本,用户可以在 ListView 中添加更多选项,然后单击搜索以发送根据用户选项构建的 sql 查询。

我发现 convertView 混合不合理,所以我在活动中添加了一个全局列表(myViews)并将其传递给 ArrayAdapter。然后在 ArrayAdapter (getView) 中添加每个新添加的视图 (myViews)。

同样在 getView 上,而不是检查 convertView 是否为空,我检查全局列表(myViews)是否对所选(位置)有一个视图。它在失去 3 天阅读互联网后完全解决了问题!

1-在活动上添加这个:

Map<Integer, View> myViews = new HashMap<>();

然后使用适配器构造函数将其传递给 ArrayAdapter。

mSOAdapter = new SearchOptionsAdapter(getActivity(), resultStrs, myViews);

2- 在 getView 上:

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

    View view;
    ViewHolder viewHolder;

    if (!myViews.containsKey(position)) {
        viewHolder = new ViewHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        view = inflater.inflate(R.layout.search_options, parent, false);

        /// ...... YOUR CODE

        myViews.put(position, view);

        FontUtils.setCustomFontsIn(view, getContext().getAssets());

    }else {
        view = myViews.get(position);
    }

    return view;
}

终于不再混合项目了......

于 2015-09-03T14:47:03.523 回答