最近遇到的一个小需求,可以简化为该模型,因此写一个Demo以记录。其实比较简单,主要利用Selector,只是网上找了一番也没找到ListView在点击后背景色一直是checked的,大多数是pressed效果(点击瞬间变背景),或者是利用RadioButton or CheckBox之类,这些都不是我想要的。
先放效果图:
分析:
最简单的ListView,其中条目View继承了CheckedTextView。该类实现了Checkable接口,调用其setChecked方法可以匹配selector中android:state_checked="true"属性,做到点击后效果保持。因此也可以自定义View实现Checkable,实现setChecked()、isChecked()、toggle()三个方法即可:
public void toggle() { setChecked(!mChecked); } public boolean isChecked() { return mChecked; } public void setChecked(boolean checked) { if (mChecked != checked) { mChecked = checked; refreshDrawableState(); notifyAccessibilityStateChanged(); } }
做到单选效果,本来我是想到用比较笨的方法,即点击时遍历ItemView,消除其他所有item 的checked状态;还想到了定义一个lastCheckedView变量记录上一次被点击的,再次点击时消除Checked状态。。后来发现只需要在Adapter中getView时判断position,然后notify刷新即可。
如果要实现多选效果,在点击时直接toggle即可,不需要考虑消除其他item状态。
代码如下:
MainActivity.java
public class MainActivity extends Activity { private ListView mListView; private ListViewAdapter<String> mAdapter; private static String[] strs = { "Felix", "Jane", "Tom", "Bob", "Jason", "Christina", "Susan", "Felix", "Jane", "Tom", "Bob", "Jason", "Christina", "Susan", "Felix", "Jane", "Tom", "Bob", "Jason", "Christina", "Susan" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (ListView) findViewById(R.id.lv); mAdapter = new ListViewAdapter<String>(this, Arrays.asList(strs)); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (view instanceof CheckedTextView) { mAdapter.setCheckedAtPosition(position); mAdapter.notifyDataSetChanged(); } } }); // lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); } }
ListViewItemView.java
public class ListViewItemView extends CheckedTextView { public ListViewItemView(Context context) { super(context); initView(); } public ListViewItemView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(); } public ListViewItemView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } private void initView(){ this.setPadding(40, 10, 10, 10); this.setTextSize(30); this.setBackgroundResource(R.drawable.item_selector); } }
ListViewAdapter.java
public class ListViewAdapter <T> extends BaseAdapter { private List<T> list; private Context context; private int checkedPos = -1; public ListViewAdapter(Context context, List<T> asList) { this.list = asList; this.context = context; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView == null){ convertView = new ListViewItemView(context); } ((TextView)convertView).setText((CharSequence) getItem(position)); if(checkedPos == position){ //说明该位置需要checked ((ListViewItemView)convertView).setChecked(true); }else{ //不需要checked ((ListViewItemView)convertView).setChecked(false); } return convertView; } /** * 设置哪一个条目被选中 * @param pos */ public void setCheckedAtPosition(int pos){ this.checkedPos = pos; } }
xml文件
主要是selector
<item android:drawable="@color/wheat" android:state_checked="true"/> <!-- 代表选中状态 --> <item android:state_pressed="true" android:drawable="@color/blanchedalmond"/> <!-- 代表点击状态 --> <item android:drawable="@color/blanchedalmond"></item> <!-- 默认背景 -->