ListView in ArrayAdapter order get's mixed up when scrolling

后端 未结 4 1869
清酒与你
清酒与你 2020-11-27 05:11

I have a ListView in a custom ArrayAdapter that displays an icon ImageView and a TextView in each row. When I make the list long enough to let you scroll through it, the or

相关标签:
4条回答
  • 2020-11-27 05:36

    To further clarify the answer of farcats below in more general way, here is my explanation:

    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.

    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.

    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. 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

    0 讨论(0)
  • 2020-11-27 05:41

    I have a ListView, AdapterView and a View (search_options) that contains EditText and 3 Spinners. 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.

    I found that convertView mixing indecies so I added a global list (myViews) in activity and passed it to ArrayAdapter. Then in ArrayAdapter (getView) I add every newly added view to it (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!!

    1- on Activity add this:

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

    and then pass it to ArrayAdapter using adapter constructor.

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

    2- on 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...

    0 讨论(0)
  • 2020-11-27 05:44

    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. I was getting the view from the convertedView, and if it was null, that's when I'd build my stuff. 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.

    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.

    0 讨论(0)
  • 2020-11-27 05:44

    The ListView reuses view objects when you scroll. Are you overriding the getView method? 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.

    0 讨论(0)
提交回复
热议问题