简体   繁体   中英

ListView items changes when scrolling

I'm filling a listview, here is the code :

ArrayAdapter<CharSequence> listAdapter1;
ListView toc;
toc=(ListView)findViewById(R.id.listView1);
listAdapter1=ArrayAdapter.createFromResource(Glossary.this,R.array.arabicalphabet,R.layout.glossarysimplerow);
toc.setAdapter(listAdapter1);

I'm setting a list selector in the xml file, when clicking on any item in the list its color will change to blue to show that it is selected. The problem is, when I scroll the listview the selection will change, for example if I have a list filled from A to Z, If I select the letter "B" and I scroll many times, I get the letter "M" selected... Any help please

yah, I encounted this problem a week ago, the reason is "when you scroll listview, the first display item has position 0", so your change view will affect on the new item.

My solution is:

1). Using ScrollView with a LinearLayout inside it instead of using ListView

2). Add array TextView[] to LinearLayout .

code:

Layout:

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="2dp"
    android:layout_marginRight="2dp"
    android:layout_marginTop="5dp"
    android:layout_marginBottom="5dp">
    <LinearLayout
        android:id="@+id/ll_inflater"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </LinearLayout>
</ScrollView>

Java:

int prePos = -1;
int sdk = android.os.Build.VERSION.SDK_INT;
LinearLayout ll_inflater = (LinearLayout)findViewById(R.id.ll_inflater);
TextView[] tv_Subs = new TextView[array.size()];//arrary is arrayData
for(int i = 0; i < array.size(); i++){
    tv_Subs[i] = new TextView(getApplication());
    tv_Subs[i].setLines(3);
    tv_Subs[i].setTextColor(getResources().getColor(R.color.sub_color));
    tv_Subs[i].setGravity(Gravity.CENTER);

    if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
        //set default background color
    } else {
        //set default background color
    }

    tv_Subs[i].setText(array.get(i));
    ll_inflater.addView(tv_Subs[i], i, new  ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    final int finalI = i;
    tv_Subs[i].setOnClickListener( new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(prePos !=-1){
                 //change background of preposition tv_Subs[prePost] to default color
            }
            //change background color here
            prePos = finalI;
        }
    });
}

In Android the children of AdapterView like ListView have caching enabled, so when user scrolls, the items off the screen are off the memory, getView() is called for the items that are to be shown on the view after scrolling.

The View that is passed in the getView() method is reused and has properties of the previously visible view s in the ListView . This improves the performance of the ListView but makes it necessary to check for all the possible conditions and reset all the properties of the view received in the getView() .

Now the generic ArrayAdapter that you used has no implementation of changing colors on click and it doesn't have any way to keep a record of the view already clicked. So on scrolling the results are unexpected.

You may implement your own Adapter class as shown below and it will solve your issue:

public class MyAdapter extends ArrayAdapter<String> {
    Context context;
    List<String> lstStrings;
    List<Boolean> isClicked;

    public MyAdapter (Context context, int resource, List<String> lstStrings) {
        super(context, resource, lstStrings);
        this.context = context;
        lstStrings = lstStrings;
        isClicked = new ArrayList<>(Arrays.asList(new Boolean[lstStrings.length]));
        Collections.fill(isClicked, new Boolean(false));
    }   

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

    @Override
    public String getItem(int position) {
        return lstStrings.get(position);
    }

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        if (convertView == null)
            convertView = LayoutInflater.from( context).inflate(R.layout.list_item, null);

        TextView txtTheText = (TextView) convertView.findViewById(R.id.txtTheText);

        txtTheText .setText(lstStrings.get(position));

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                isClicked.set(!isClicked.get(position));
            }
        });

        if (isClicked.get(position))
            convertView.setBackgroundColor(Color.argb(255, 255, 0, 0));
        else
            convertView.setBackgroundColor(Color.argb(255, 0, 0, 255));

        return convertView;
    }
}

I have a resolution. When you click one item, record its position . Then override onConfigurationChanged(Configuration newConfig) , and call ListView.setSelection(position) .

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