如何在触摸模式(Touch Mode)下高亮显示ListView选中行
这应该是大部分Android开发者在使用ListView时会碰到问题,在解决这个问题前,需要先了解什么叫触摸模式。
触摸模式(Touch Mode),在Android SDK的官方文档中有详细解释(http://developer.android.com/resources/articles/touch-mode.html),其大概内容如下:
• 用户通过触摸屏操作设备时,设备将自动进入触摸模式,相对的,使用键盘、轨迹球等其他设备时,设备处于非触摸模式
• 进入触摸模式后,View将失去焦点(Focus)和选择(Selection)状态(文本输入框是例外),原因是Android的设计者没有好的办法解决同时操作触摸屏和轨迹球、键盘等外部设备所带来的混乱状态
• Android的设计者认为进入触摸模式后,View失去焦点和选择状态不是一个需要修正的问题,开发者也不应该在触摸模式中试图保持View的焦点或选择状态,可以使用CheckBox或RadioButton等控件来标识选择状态
这种设计策略可以说完全是从工程师的思维而不是从用户的需求去考虑问题,新的手机的性能越来越强,屏幕分辨率越来越高,应用程序界面设计趋向复杂,使用触摸屏操作时居然连个高亮显示都无法做到,真是件十足坑爹的事。
考察了几种不同的实现后,评估其性能代价和解决方式的优雅程度,我决定用checked状态来模拟选择选择selection来实现ListView的选中行的高亮显示:
1. 将ListView设为CHOICE_MODE_SINGLE或CHOICE_MODE_MULTIPLE,使ListView支持checked/unchecked状态
2. 在ListView的适配器中,返回的View实现Checkable接口,跟随选中状态的改变而改变自身背景
下面是我的测试代码:
001 package org.noodies;
002
003 import android.app.Activity;
004 import android.content.Context;
005 import android.graphics.drawable.Drawable;
006 import android.graphics.drawable.StateListDrawable;
007 import android.os.Bundle;
008 import android.view.View;
009 import android.view.ViewGroup;
010 import android.widget.BaseAdapter;
011 import android.widget.Checkable;
012 import android.widget.ListView;
013 import android.widget.TextView;
014
015 public class TestListActivity extends Activity {
016
017 private ListView mListView;
018
019 @Override
020 public void onCreate(Bundle savedInstanceState) {
021 super.onCreate(savedInstanceState);
022 setContentView(R.layout.main);
023
024 mListView = (ListView) findViewById(R.id.listView1);
025
026 // 设为单选,允许列表项切换checked/unchecked状态
027 mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
028 // 列表的选择效果设为透明,由列表项自行维护各状态显示
029 mListView.setSelector(android.R.color.transparent);
030
031 mListView.setAdapter(new TestAdapter());
032 }
033
034 private class MyView extends TextView implements Checkable {
035
036 private final int[] STATE_CHECKED = { android.R.attr.state_checked };
037
038 private int[] mSavedState;
039 private boolean mChecked = false;
040
041 public MyView(Context context) {
042 super(context);
043 }
044
045 public void setChecked(boolean checked) {
046 if (mChecked != checked) {
047 mChecked = checked;
048 updateBackground();
049 }
050 }
051
052 public boolean isChecked() {
053 return mChecked;
054 }
055
056 public void toggle() {
057 setChecked(!mChecked);
058 }
059
060 private void updateBackground() {
061 Drawable bg = this.getBackground();
062
063 // 在这里切换checked/unchecked状态
064 if (bg.getClass().equals(StateListDrawable.class)) {
065 if (isChecked()) {
066 mSavedState = bg.getState();
067 bg.setState(STATE_CHECKED);
068 } else if (mSavedState != null) {
069 bg.setState(mSavedState);
070 }
071 }
072 }
073 }
074
075 private class TestAdapter extends BaseAdapter {
076
077 private String[] testData = { "test1", "test2", "abcd", "abcdefg" };
078
079 public int getCount() {
080 return testData.length;
081 }
082
083 public Object getItem(int position) {
084 return testData[position];
085 }
086
087 public long getItemId(int position) {
088 return 0;
089 }
090
091 public View getView(int position
补充:移动开发 , Android ,