ListView items change when scrolling
I am filling the list, 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 am setting a list selector in the xml file, when clicking on any item in the list, its color changes to blue to show that it is selected. The problem is that when I scroll through the list, the selection will change, for example if I have a list filled out from A to Z. If I select the letter "B" and I scroll many times, I get the letter "M" selected .. . Any help please
source to share
yah, I discovered this issue a week ago, the reason is "when you view the listview, the first display item is at position 0", so your change will affect the new item.
My decision:
1). Using ScrollView
with LinearLayout
inside it instead of usingListView
2). Add the array TextView[]
to LinearLayout
.
code:
Markup:
<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;
}
});
}
source to share
In Android, children AdapterView
like have ListView
caching enabled, so when the user scrolls, items from the screen go out of memory, getView()
called for items to be displayed in the view after scrolling.
View
that is passed in the method getView()
is reused and has the properties previously visible View
in ListView
. This improves performance ListView
, but requires checking all possible conditions and resetting all view properties retrieved from getView()
.
Now the generic ArrayAdapter
one you used has no implementation of changing colors on click, and it has no way to keep a record of the view already clicked. Thus, when scrolling, the results are unexpected.
You can implement your own class Adapter
like below and it will solve your problem:
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;
}
}
source to share