Android学习小Demo(21)ListView的联动选择
在日常的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的状态,例如以下:
@Override
public 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() {
@Override
public 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() {
@Override
public 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的目的是为了将这个button的操作事件传递给调用者,由于当选择完之后,兴许的处理逻辑应该由调用者来处理。
/**
* 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() {
@Override
public 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;
@Override
protected 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 view
Intent intent = getIntent();
String leftValue = intent.getStringExtra(SELECTED_LEFT);
String rightValue = intent.getStringExtra(SELECTED_RIGHT);
vpTest.setLeftValue(leftValue);
vpTest.setRightValue(rightValue);
vpTest.initialize();
}
@Override
public 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的联动选择的更多相关文章
- Android学习小Demo(19)利用Loader来实时接收短信
之前写过一篇文章<Android学习小Demo(13)Android中关于ContentObserver的使用>,在里面利用ContentOberver去监測短信URI内容的变化.我们先来 ...
- Android学习小Demo一个显示行线的自定义EditText
今天在处理一个EditText的时候,想着把EditText做成像一本作业本上的纸一样,每一行都可以由线条隔开,具体效果如下: 1)最开始的思路 一开始的想法是很简单的,找出每一行的高度,然后一行一行 ...
- Android学习小Demo(20)关于Fragment的应用
Android在3.0之后引入了Fragment的概念,我推測其想法可能仅仅是想更好地兼容大屏幕或者平板的开发,由于大屏幕能够展示很多其它的内容,而内容一多,逻辑有可能就乱,而利用Fragment,则 ...
- RPC框架学习+小Demo实例
一.什么是RPC协议? 全称:远程过程调度协议 效果:使消费者向调用本地方法一样调用远程服务方法,对使用者透明 目前常用:Dubbo.Thirft.Sofa.... 功能: 建立远程通信(socket ...
- android学习--视图列表(ListView和ListActivity)
说明: 视图列表(ListView和ListActivity)与AutoComplete.Spinner类似,它们都须要一个供显示的列表项,能够须要借助于内容Adapter提供显示列表项 创建List ...
- 小程序--wepy省市区三级联动选择
产品老哥对项目再一次进行关爱, 新增页面, 新增需求, 很完美........ 不多说, 记录一下新增东西中的省市区联动选择, (这里全国地区信息是在本地, 但不建议这么做, 因为js文件太大.. 建 ...
- 高强度学习训练第二天总结:Opencv+Android+CameraView小demo
前言:网上已经有很多人将Opencv集成进Android项目中了.因此我只给大家看Gradle文件和项目目录. 1.gradle 三个gradle script // Top-level build ...
- Android学习笔记(20)————利用ListView制作带竖线的多彩表格
http://blog.csdn.net/conowen/article/details/7421805 /********************************************** ...
- Android学习之sqlite与listview
在android系统中使用的是sqlite数据库,前面的简易登录系统已经讲述了数据库的应用.本例的重点是实现数据库与listview的绑定.demo的数据是将个人的信息绑定到listview中,并存在 ...
随机推荐
- jsp、Servlet相关知识介绍(转)
1.servlet生命周期 所谓生命周期,指的是servlet容器如何创建servlet实例.分配其资源.调用其方法.并销毁其实例的整个过程. 阶段一: 实例化(就是创建servlet对象,调用构造器 ...
- tomcatserver乱码问题,tomcat与数据库之间的编码统一转换
在tomcat文件夹的conf文件夹下,改动server.xml文件,在以下截图中的位置加上URIEncoding="UTF-8"则表示tomcat编码转换为utf-8风格, 一般 ...
- js 性能优化整理之 高频优化
mousemove 拖拽操作 var count = 0; elem.onmousemove = function(){ count++; // 当计数器为偶数的时候不执行mousemove if( ...
- 采用Flume实时采集和处理数据
它已成功安装Flume在...的基础上.本文将总结使用Flume实时采集和处理数据,详细过程,如下面: 第一步,在$FLUME_HOME/conf文件夹下,编写Flume的配置文件,命名为flume_ ...
- NSIS API 函数常用备份
原文:NSIS API 函数常用备份 关闭程序: System::Call `user32::AnimateWindow(i$HWNDPARENT,i200,i${AW_BLEND}|${AW_HID ...
- Angular规范
只记录一些自己未曾用过,但觉得对以后的项目有帮助的规范 一 Javascript闭包 把Angular组件包装到一个立即调用函数表达式中(IIFE). 为什么?:把变量从全局作用域中删除了,这有助于 ...
- How to recover from 'programmers burnout(转)
程序员这个压力大,节奏快,任务繁重,所以很容易令人感觉倦怠,令人感觉烦躁,郁闷,疲惫不堪. 本文将介绍的是程序员如何克服可怕的“职业倦怠”. 丰盛的早餐——身处高科技产业漩涡的我们常常会熬夜到凌晨两三 ...
- 计数排序(C语言版本)
让我们来谈谈数的排序思维: 计数排序假定待排序的全部元素都是介于0到K之间的整数.计数排序使用一个额外的数组countArray.当中第i个元素是待排序数组array中值等于i的元素的个数.然后依据数 ...
- 沃森Mysql数据库修复工具
华信Mysql数据库修复程序是由北京华信数据恢复中心独立研发.主要针对Mysql数据库损坏的恢复. 本程序可用于因为各种误操作而导致数据丢失的恢复,以及因为断电.陈列损坏.硬盘坏道等各种原因导致数据库 ...
- 在vc正在使用xtremetoolkit接口库-----使用简单的控制
首先,我们需要在StdAfx.h增加头文件: #include "XTToolkitPro.h" #include "XTPResource.h" 在test. ...