简体   繁体   English

滚动时ArrayAdapter中的ListView顺序混乱

[英]ListView in ArrayAdapter order get's mixed up when scrolling

I have a ListView in a custom ArrayAdapter that displays an icon ImageView and a TextView in each row. 我在自定义ArrayAdapter中有一个ListView,该数组在每行中显示一个ImageImageView和一个TextView。 When I make the list long enough to let you scroll through it, the order starts out right, but when I start to scroll down, some of the earlier entries start re-appearing. 当我使列表足够长以使您可以滚动列表时,该顺序从右开始,但是当我开始向下滚动时,一些较早的条目开始重新出现。 If I scroll back up, the old order changes. 如果我向上滚动,旧的顺序会改变。 Doing this repeatedly eventually causes the entire list order to be seemingly random. 重复执行此操作最终会导致整个列表顺序看似随机。 So scrolling the list is either causing the child order to change, or the drawing is not refreshing correctly. 因此,滚动列表会导致子顺序更改,或者图形无法正确刷新。

What could cause something like this to happen? 什么会导致这种情况发生? I need the order the items are displayed to the user to be the same order they are added to the ArrayList, or at LEAST to remain in one static order. 我需要将项目显示给用户的顺序与它们添加到ArrayList的顺序相同,或者至少保持一个静态顺序。 If I need to provide more detailed information, please let me know. 如果我需要提供更多详细信息,请告诉我。 Any help is appreciated. 任何帮助表示赞赏。 Thanks. 谢谢。

I was having similar issues, but when clicking an item in the custom list, the items on the screen would reverse in sequence. 我遇到了类似的问题,但是单击自定义列表中的项目时,屏幕上的项目将依次颠倒。 If I clicked again, they'd reverse back to where they were originally. 如果我再次单击,它们会退回到原来的位置。

After reading this, I checked my code where I overload the getView method. 阅读此内容后,我检查了我的代码,在其中我重载了getView方法。 I was getting the view from the convertedView, and if it was null, that's when I'd build my stuff. 我是从convertedView获取视图的,如果它为null,那就是在构建自己的东西时。 However, after placing a breakpoint, I found that it was calling this method on every click and on subsequent clicks, the convertedView was not null therefore the items weren't being set. 但是,在放置断点后,我发现它在每次单击以及随后的单击时都调用此方法,convertedView不为null,因此未设置项目。

Here is an example of what it was: 这是一个例子:


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

The subtle change is moving the close brace for the null check on the view to just after inflating: 细微的变化是将视图上的空检查的右括号移动到膨胀后:


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

I hope this helps others who experience this same problem. 希望这对遇到同样问题的其他人有所帮助。

To further clarify the answer of farcats below in more general way, here is my explanation: 为了以更一般的方式进一步阐明以下Farcat的答案,以下是我的解释:

The vi.inflate operation (needed here for parsing of the layout of a row from XML and creating the appropriate View object) is wrapped by an if (view == null) statement for efficiency, so the inflation of the same object will not happen again and again every time it pops into view. vi.inflate操作(此处是从XML解析行的布局并创建适当的View对象所需的操作)由if(view == null)语句包装,以提高效率,因此不会发生同一对象的膨胀一次又一次地出现在视图中。

HOWEVER, the other parts of the getView method are used to set other parameters and therefore should NOT be included within the if (view == null) statement. 但是,getView方法的其他部分用于设置其他参数,因此不应包含在if(view == null)语句中。

Similarily, in other common implementation of this method, some textView, ImageView or ImageButton elements need to be populated by values from the list[position], using findViewById and after that .setText or .setImageBitmap operations. 相若方式,在其他常见的实现该方法,一些TextView的的,ImageView的或ImageButton的元件需要由值从列表[位置]填充,使用findViewById并且之后.setText.setImageBitmap操作。 These operations must come after both creating a view from scratch by inflation and getting an existing view if not null. 这些操作必须来受通胀从头开始创建一个视图,并让现有视图如果不为空后。

Another good example where this solution is applied for BaseAdapter appears in BaseAdapter causing ListView to go out of order when scrolled 另一个适用于BaseAdapter的解决方案的好示例出现在BaseAdapter中,导致滚动时ListView出现故障

The ListView reuses view objects when you scroll. 滚动时,ListView重用视图对象。 Are you overriding the getView method? 您要覆盖getView方法吗? You need to make sure you set each property for every view, don't assume that it will remember what you had before. 您需要确保为每个视图都设置了每个属性,不要以为它会记住您以前拥有的内容。 If you post that method, someone can probably point you at the part that is incorrect. 如果您发布该方法,则有人可能会指出您不正确的部分。

I have a ListView, AdapterView and a View (search_options) that contains EditText and 3 Spinners. 我有一个ListView,AdapterView和一个包含EditText和3 Spinners的视图(search_options)。 ListView items are multiple copies of (search_options) layout, where user can add more options in ListView then click search to send sql query built according to users options. ListView项目是(search_options)布局的多个副本,用户可以在ListView中添加更多选项,然后单击“搜索”以发送根据用户选项构建的sql查询。

I found that convertView mixing indecies so I added a global list (myViews) in activity and passed it to ArrayAdapter. 我发现convertView的混合效果不确定,因此我在活动中添加了一个全局列表(myViews),并将其传递给ArrayAdapter。 Then in ArrayAdapter (getView) I add every newly added view to it (myViews). 然后在ArrayAdapter(getView)中,将每个新添加的视图添加到其中(myViews)。

Also on getView instead of checking if convertView is null, I check if the global list (myViews) has a view on the selected (position).. It totally solved problems after losing 3 days reading the internet!! 同样在getView上,而不是检查convertView是否为null,我检查全局列表(myViews)是否具有选定位置(位置)上的视图。在丢失三天的互联网阅读时间后,它完全解决了问题!

1- on Activity add this: 1-在活动上添加以下内容:

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

and then pass it to ArrayAdapter using adapter constructor. 然后使用适配器构造函数将其传递给ArrayAdapter。

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

2- on getView: 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;
}

Finally no more mixing items... 终于没有更多的混合项目了...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM