在日常的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的联动选择的更多相关文章

  1. Android学习小Demo(19)利用Loader来实时接收短信

    之前写过一篇文章<Android学习小Demo(13)Android中关于ContentObserver的使用>,在里面利用ContentOberver去监測短信URI内容的变化.我们先来 ...

  2. Android学习小Demo一个显示行线的自定义EditText

    今天在处理一个EditText的时候,想着把EditText做成像一本作业本上的纸一样,每一行都可以由线条隔开,具体效果如下: 1)最开始的思路 一开始的想法是很简单的,找出每一行的高度,然后一行一行 ...

  3. Android学习小Demo(20)关于Fragment的应用

    Android在3.0之后引入了Fragment的概念,我推測其想法可能仅仅是想更好地兼容大屏幕或者平板的开发,由于大屏幕能够展示很多其它的内容,而内容一多,逻辑有可能就乱,而利用Fragment,则 ...

  4. RPC框架学习+小Demo实例

    一.什么是RPC协议? 全称:远程过程调度协议 效果:使消费者向调用本地方法一样调用远程服务方法,对使用者透明 目前常用:Dubbo.Thirft.Sofa.... 功能: 建立远程通信(socket ...

  5. android学习--视图列表(ListView和ListActivity)

    说明: 视图列表(ListView和ListActivity)与AutoComplete.Spinner类似,它们都须要一个供显示的列表项,能够须要借助于内容Adapter提供显示列表项 创建List ...

  6. 小程序--wepy省市区三级联动选择

    产品老哥对项目再一次进行关爱, 新增页面, 新增需求, 很完美........ 不多说, 记录一下新增东西中的省市区联动选择, (这里全国地区信息是在本地, 但不建议这么做, 因为js文件太大.. 建 ...

  7. 高强度学习训练第二天总结:Opencv+Android+CameraView小demo

    前言:网上已经有很多人将Opencv集成进Android项目中了.因此我只给大家看Gradle文件和项目目录. 1.gradle 三个gradle script // Top-level build ...

  8. Android学习笔记(20)————利用ListView制作带竖线的多彩表格

    http://blog.csdn.net/conowen/article/details/7421805 /********************************************** ...

  9. Android学习之sqlite与listview

    在android系统中使用的是sqlite数据库,前面的简易登录系统已经讲述了数据库的应用.本例的重点是实现数据库与listview的绑定.demo的数据是将个人的信息绑定到listview中,并存在 ...

随机推荐

  1. 使用JS意识到自己主动提交表单

    今天将需要chat集成到客户的网站上去,注册用户链接登录这个网站后点击实现网站直接登录chat向上.我不停chat原来的登录界面,采纳JS当页面跳转技术,随着时间的推移自己主动填写表格.自己主动提交表 ...

  2. OCP-1Z0-051-标题决心-文章2称号

    2. View the Exhibit to examine the description for the SALES table. Which views can have all DML ope ...

  3. ASP.NET Identity

    使用ASP.NET Identity实现基于声明的授权 阅读目录 走进声明的世界 创建并使用声明 基于声明的授权 使用第三方来身份验证 小节 在这篇文章中,我将继续ASP.NET Identity 之 ...

  4. linux内核包转发过程(三)NIC帧接收分析

    [版权声明:转载请保留源:blog.csdn.net/gentleliu.邮箱:shallnew*163.com] 每一个cpu都有队列来处理接收到的帧.都有其数据结构来处理入口和出口流量,因此.不同 ...

  5. Leetcode 动态规划 Candy

    本文senlie原版的,转载请保留此地址:http://blog.csdn.net/zhengsenlie Candy Total Accepted: 16494 Total Submissions: ...

  6. Display Database Image using MS SQL Server 2008 Reporting Services

    原文 Display Database Image using MS SQL Server 2008 Reporting Services With the new release of MS SQL ...

  7. PL/SQL 9 许可证

    code:j6stndb9tk72xfbhbqczcdqnjd8lyj466n number:882851 ps:xs374ca 我是PL/SQL版本号是: Version 9.0.3.1641 要注 ...

  8. VS2015, .NET 4.6, C# 6.0, F# 4.0等重量级产品正式上线

    VS2015, .NET 4.6, C# 6.0, F# 4.0等重量级产品正式上线 Visual Studio Visual Studio 2015 下载 VS2015新功能列表 ‘ Visual ...

  9. NYNU_省赛选拔题(6)

    题目描述 有一天,小米找到了一个藏宝的迷宫地图,迷宫在一个沙漠里有,迷宫里面有许多宝藏.迷宫里可能有N个藏宝地点,用1到K标记.藏宝地点之间最多有一条通路相连.标记1为迷宫的进出口. 他已经知道其中K ...

  10. Oracle 11g XE 是 Oracle 数据库的免费版本

    Oracle 11g XE 是 Oracle 数据库的免费版本,支持标准版的大部分功能,11g XE 提供 Windows 和 Linux 版本. 做为免费的 Oracle 数据库版本,XE 的限制是 ...