Android ListView选中某一行修改其背景色时,在原生的ListView类中有一个listSelector属性可实现此效果,不过发现有BUG。开始以为是Android版本太低(Android 2.3 其中有BUG)所以换成高版本(4.3) 做了个测试。发现BUG依然存在。估计是Android系统在ListView中一直存在的BUG。
需求:
当点击某一行(第三行)时,第三行背景色变为绿色,当点击事件完成以后就一直保持为绿色的状态。只有当点击了其他行(第10行)的时候第三行的颜色才恢复为原来的颜色(白色),然后第十行的颜色修改为绿色
BUG描述如下:
假设当选中列表项第二行的时候,第二行背景色修改为绿色。然后快速(注:一定非常快且ListView的列表项比较多才会出现此BUG)向下滑动ListView,此时会在比如在第60行背景色变为绿色(且不一定总是在第60行)。
经过几天的研究终于修复此问题,代码如下:
TestActivity.java
public class TestActitvty extends Activity implements OnItemClickListener{
ListView listview;
ArrayAdapter<Map<String, String>> adapter;
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
private View selectedView;
private Integer index;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message message) {
@SuppressWarnings("unchecked")
List<Map<String, String>> l = (List<Map<String, String>>) message.obj;
data.addAll(l);
adapter.notifyDataSetChanged();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
listview = (ListView) findViewById(R.id.listview);
adapter = new MyArrayAdapter(this, R.layout.activity_test_item, data);
listview.setAdapter(adapter);
listview.setOnItemClickListener(this);
handler.post(new Runnable() {
@Override
public void run() {
Message m = new Message();
m.what = 5;
List<Map<String, String>> l = new ArrayList<Map<String,String>>();
for(int i=0; i<100; i++){
Map<String, String> map = new HashMap<String, String>();
map.put("name", "name_"+i);
l.add(map);
}
m.obj = l;
handler.dispatchMessage(m);
}
});
}
private class MyArrayAdapter extends ArrayAdapter<Map<String, String>> {
private List<Map<String, String>> list;
public MyArrayAdapter(Context context, int resource, List<Map<String, String>> list) {
super(context, resource, list);
this.list = list;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder = null;
if(convertView == null){
holder = new Holder();
convertView = LayoutInflater.from(getApplicationContext()).inflate(R.layout.activity_test_item, null);
holder.name = (TextView)convertView.findViewById(R.id.item);
convertView.setTag(holder);
}else{
holder = (Holder) convertView.getTag();
}
Map<String, String> map = this.list.get(position);
holder.name.setText(map.get("name").toString());
Resources resources = getResources();
// 判断当前重画行与被选中行是否是同一行
// 如是则修改当前重画的行背景为绿色
// 如不是则为默认白色
if(index!=null && position==index){
convertView.setBackgroundColor(resources.getColor(R.color.txt_green));
// 注:此行不能少,否则会有新的BUG(本人开始的时候就是在此处没重新在此做缓存,导致新的BUG出现。结果纠结了几天。)
// 具体是什么BUG自己研究吧
selectedView = convertView;
}else{
convertView.setBackgroundColor(resources.getColor(R.color.txt_white));
}
return convertView;
}
class Holder {
TextView name;
}
}
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Resources resources = getResources();
// 修改当前选中行背景色为绿色
view.setBackgroundColor(resources.getColor(R.color.txt_green));
if(this.selectedView!=null && this.index!=position){
// 修改原被选中行为白色
selectedView.setBackgroundColor(resources.getColor(R.color.txt_white));
}
// 修改被选中行的缓存数据
this.selectedView = view;
this.index = position;
}
}
布局文件
activity_test_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item"
android:padding="10dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</TextView>
activity_test.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
其他string.xml简单,这里几不贴代码了