Android学习小Demo(21)ListView的联动选择
来源:互联网 发布:java输出hello world 编辑:程序博客网 时间:2024/06/05 07:52
在日常的App开发中,尤其是在开发生活服务的应用上,很多时候,我们会需要联动地展现省市区的数据等,需求大概如下:
1)展现所有省份
2)当点击某省份的时候,在二级菜单上展现此省份下面所属的城市列表
3)选中返回,显示我们选中的城市
4)当重新进入选择页面的时候,标识出我们上一次选中(或者说当前已经选择)的值
下图是一个类似的ListView联动选择控件。
1)首先定义一个Layout,左右各放置一个ListView,大概界面如下:
2)自定义一个控件(ValuePicker),在控件中,首先我们要获取填充两个ListView的数据,如果在是省市的话,就要获取省市的数据,在这个Demo中,我们利用DataProvider这个类,来模拟一些数据,如下:
public class DataProvider {public static final String[] summaries = {"A","B","C","D","E","F","G","H"};public static final Map<String, String[]> details = new HashMap<>(); static { details.put("A",new String[] {"A1", "A2", "A3"}); details.put("B",new String[] {"B1", "B2", "B3"}); details.put("C",new String[] {"C1", "C2", "C3"}); details.put("D",new String[] {"D1", "D2", "D3"}); details.put("E",new String[] {"E1", "E2", "E3"}); details.put("F",new String[] {"F1", "F2", "F3"}); details.put("G",new String[] {"G1", "G2", "G3"}); details.put("H",new String[] {"G1", "H2", "H3"});}}
然后在ValuePicker中引用这些数据。
private String[] summaries = DataProvider.summaries;private Map<String, String[]> details = DataProvider.details;
3)要将数据绑定到对应的ListView上面,我们必须分别为这两个ListView声明一个Adapter,在这里,我们继承BaseAdapter,创建一个SingleCheckedListAdpater。
由于Android本身提供的ListView是没有选中的效果的,而基于我们的需求,
3.1)需要在用户点击Item的时候,设置Item选中的状态,在这里,我们是利用"黑底白字",反转颜色来突出显示的效果。
3.2)而当我们点击另外一个Item的时候,需要将原来的Item重新置为未选中的状态,即要重新设置其背景和字体颜色,重新变成“白底黑字”,而将当前新选中的Item置为选中。
3.3)一种特殊情况是,ListView里面的个数超出当前屏幕的话,当我们滑动ListView的时候,ListView是会复用我们之前已经创建过的View的,所以,我们必须对选中的Item做一个特殊处理。被选中的Item,如果滑出屏幕,其对应的View是会被复用的,所以必须在其被复用的时候,将其置为未选中状态,而当其重新滑入屏幕的时候,将其置为选中状态。
基于以上几种情况,我们需要在Adapter中记录下某个被选中的Item的位置和View,代码如下:
/** * the View checked */private TextView mLastCheckedView = null;/** * the position in the data */private int mCheckedPosition = -1;public void setCheckedPosition(int position){mCheckedPosition = position;}.../** * @param checkedView the checkedView to set */public void setCheckedView(View checkedView) {setViewSelected(mLastCheckedView, false);TextView textView = (TextView)checkedView;setViewSelected(textView, true);}private void setViewSelected(TextView view, boolean selected){if(view != null){if(selected){view.setBackgroundColor(mContext.getResources().getColor(R.color.black));view.setTextColor(mContext.getResources().getColor(R.color.white));mLastCheckedView = view;}else{view.setBackgroundColor(mContext.getResources().getColor(R.color.white));view.setTextColor(mContext.getResources().getColor(R.color.black));}}}
在getView的时候,根据是否选中的位置来处理View的状态,如下:
@Overridepublic View getView(int position, View convertView, ViewGroup root) {ViewHolder holder = null;if (convertView == null) {holder = new ViewHolder();convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item_card_number, null);holder.name = (TextView) convertView.findViewById(R.id.textView1);convertView.setTag(holder);}else{holder = (ViewHolder) convertView.getTag();}setViewSelected(holder.name, mCheckedPosition == position);holder.name.setText(mData[position]);return convertView;}
另外,由于是联动的ListView,当左边的某个Item被点击的时候,右边的ListView要对应的刷新数据,所以Adapter也必须提供对应的入口去刷新数据。
public void setData(String[] data){mData = data;mLastCheckedView = null;mCheckedPosition = -1;notifyDataSetChanged();}
4)而很显然,我们也必须在ValuePicker这个控件中,记录下选中的值,才能够在数据源中查找出其对应的位置,并将其传递给Adapter。因此,我们在ValuePicker中会定义两个位置和对应的值。
private int mPosLeft = -1;private String mCurLeft;private int mPosRight = -1;private String mCurRight;
这只是在这个Demo中简单的定义,在具体的应用上,这几个变量可根据具体的业务信息自定义变量名。
以下代码为找出对应的位置。
for(int i = 0; i < len; i++){String summary = summaries[i];if(summary.equals(mCurLeft)){mPosLeft = i;break;}}if(mPosLeft >= 0){String summary = summaries[mPosLeft];String[] right = details.get(summary);int lenOfRight = right.length;for(int j = 0; j < lenOfRight; j++){String detail = right[j];if(mCurRight != null && detail.equals(mCurRight)){mPosRight = j;break;}}}
接着在ListView绑定Adapter的时候,我们需要将这个值传过去,在这里不用去关心其值,因为在Adapter中会进行处理。
final SingleCheckedListAdapter lAdapter = new SingleCheckedListAdapter(mContext, summaries);lAdapter.setCheckedPosition(mPosLeft);lvLeft.setAdapter(lAdapter);String[] rights = new String[]{};if(mPosLeft >= 0 && mPosRight >= 0){rights = details.get(summaries[mPosLeft]);}final SingleCheckedListAdapter rAdapter = new SingleCheckedListAdapter(mContext, rights);rAdapter.setCheckedPosition(mPosRight);lvRight.setAdapter(rAdapter);在上面也有一点要注意的就是,当左边值有选中的时候,我们要将其对应的右边的ListView的内容也给找出来,并将其绑定到右边的ListView中。
而在OnItemClickListener中,我们就要根据我们选中的位置,重新去置这个值。
lvLeft.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View view, int position, long id) {mCurRight = null;lAdapter.setCheckedPosition(position);lAdapter.setCheckedView(view);mPosLeft = position;rAdapter.setData(details.get(summaries[mPosLeft]));}});lvRight.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View view, int position, long id) {rAdapter.setCheckedPosition(position);rAdapter.setCheckedView(view);mCurRight = details.get(summaries[mPosLeft])[position];}});
最后,在ValuePicker中,我们还定义了一个OnClickListener,这个listener的目的是为了将这个按钮的操作事件传递给调用者,因为当选择完之后,后续的处理逻辑应该由调用者来处理。
/** * Listener to handle the logic when current city card number is selected */public OnClickListener mListener;/** * @param listener the listener to set */public void setButtonOnClickListener(OnClickListener listener) {this.mListener = listener;}...btnConfirm.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {if(mListener != null){mListener.onClick(arg0);}}});
5)当上述一切都实现了之后,这个自定义的联动ListView选择控件也就完成了,可以在layout中使用它了,如下:
<com.lms.twofoldselector.ValuePicker android:id="@+id/vpTest" android:layout_width="match_parent" android:layout_height="match_parent" > </com.lms.twofoldselector.ValuePicker>
在Activity中初始化它,如下:
public class ValuePickerMockActivity extends Activity implements OnClickListener{public static final String SELECTED_LEFT = "SELECTED_LEFT";public static final String SELECTED_RIGHT = "SELECTED_RIGHT";private ValuePicker vpTest;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_vp_mock);vpTest = (ValuePicker) findViewById(R.id.vpTest);vpTest.setButtonOnClickListener(this);//set the selected viewIntent intent = getIntent();String leftValue = intent.getStringExtra(SELECTED_LEFT);String rightValue = intent.getStringExtra(SELECTED_RIGHT);vpTest.setLeftValue(leftValue);vpTest.setRightValue(rightValue);vpTest.initialize();}@Overridepublic void onClick(View arg0) {String rightValue = vpTest.getRightValue();if(rightValue == null){Toast.makeText(this, "请选择右边的值", Toast.LENGTH_SHORT).show();return;}Intent data = new Intent();data.putExtra(SELECTED_LEFT, vpTest.getLeftVaue());data.putExtra(SELECTED_RIGHT, vpTest.getRightValue());setResult(RESULT_OK, data);finish();}}
结束!源代码下载。
- Android学习小Demo(21)ListView的联动选择
- ListView的联动选择
- Android学习小Demo(12)TodoList实现ListView的分组实现
- listView的小demo
- Android联动ListView的实现
- Android联动ListView的实现
- Android学习笔记(二)——两个ListView联动
- Android学习小Demo(7)SharedPreference的使用
- Android学习小Demo(8)SQLiteDatabase的使用
- Android学习小Demo(10)ToDoList的加强版
- Android学习小Demo(20)关于Fragment的应用
- ListView嵌套ViewPager的小demo讲解
- 基于BaseAdapter的Listview小Demo
- 三级联动,struts2和jdbc的小DEMO
- 选择城市列表的小Demo
- 一个选择答案功能的小Demo
- listview小demo
- Android学习小Demo(13)Android中关于ContentObserver的使用
- BFS
- POJ3304-Segments
- Linux网络编程-UDP
- 第二章 构架属于自己的WMTS服务,数据下载整合篇1
- SharedPreferences详解(三)——存取图片
- Android学习小Demo(21)ListView的联动选择
- 开始程序猿之路
- 树莓派学习笔记——交叉编译练习之SQLite3安装
- vs2013配置opencv2.4.9
- 6-1. 简单计算器(20)
- 以后就在这里写技术学习笔记啦
- strcmp 遇上 string?
- 使用Socket使用域名连接服务器
- kaggel[6] - recommend missing links in a social network