简体   繁体   中英

ListView Items' background get mixed up when scrolling listView

I'm trying to change the background of a specific item in the list view titled "Different Item". As I scroll down the list, all the items' backgrounds are correct. When I reach the end of the list (where "Different Item" is), and scroll back up, there are some random items that get the same background as "Different Item". I believe this is due to the view holder pattern that I'm using and the fact that android recycles each view to use again, but I don't quite understand the issue here, and how to solve it. Here is my MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ListView listView = (ListView)findViewById(R.id.list_view);
        listView.setAdapter(new CustomAdapter(this));
    }
}

Here is my CustomAdapter.java class

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class CustomAdapter extends BaseAdapter {

    private Context mContext;
    private List<String> mItems;

    public CustomAdapter(Context context) {
        mContext = context;
        mItems = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            mItems.add("Item " + i);
        }
        mItems.add("Different Item");
    }

    @Override
    public int getCount() {
        return mItems.size();
    }

    @Override
    public Object getItem(int i) {
        return mItems.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        View view;
        ViewHolder viewHolder;
        TextView textView;

        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.list_item_template, viewGroup, false);
        } else {
            view = convertView;
        }

        if (view.getTag() == null) {
            textView = (TextView)view.findViewById(R.id.items_text_view);
            viewHolder = new ViewHolder(textView);
            view.setTag(viewHolder);
        }
        else {
            viewHolder = (ViewHolder)view.getTag();
            textView = viewHolder.getTextView();
        }

        textView.setText(mItems.get(position));

        if (mItems.get(position).equals("Different Item")) {
            textView.setBackgroundColor(Color.parseColor("#DDDDDD"));
        }

        return view;
    }

    private class ViewHolder {
        private TextView mTextView;

        public ViewHolder(TextView textView) {
            this.mTextView = textView;
        }

        public TextView getTextView() {
            return this.mTextView;
        }
    }
}

Here is my activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</RelativeLayout>

and my list_item_template.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <TextView
        android:id="@+id/items_text_view"
        android:textSize="20sp"
        android:padding="20dp"
        tools:text="test text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

and screenshots of the problem: At first, when I scroll down the list, everything looks fine:

一开始看起来不错

After scrolling the list view up and down, views get mixed up:

滚动后变得混乱

after this section :

 if (mItems.get(position).equals("Different Item")) {
            textView.setBackgroundColor(Color.parseColor("#DDDDDD"));
        }

you should have an else like this:

else
     textView.setBackgroundColor(Color.parseColor("#FFFFFF"));

it will solve your problem.

Your intuition is correct.

When you're setting the background on the "Different Item" view, at some point that view gets recycled and reused by ListView when it goes off screen, and is needed again by the adapter.

It gets reused for other items that aren't "Different Item", and if you don't explicitly reset the background to the default color for those "Item [x]" items, you will run into this problem with inconsistent backgrounds.

Also, an else statement in this context has zero impact on performance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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