Android-PickerView:仿iOS风格的高性能选择器库
Android-PickerView是一款仿iOS风格的高性能Android选择器控件库,提供了时间选择器和选项选择器两大核心功能组件。该库以其优雅的UI设计、流畅的交互体验和丰富的自定义选项,成为Android开发中处理日期时间和多级联动选择的理想解决方案。
项目概述与核心功能介绍
Android-PickerView是一款仿iOS风格的高性能Android选择器控件库,提供了时间选择器和选项选择器两大核心功能组件。该库以其优雅的UI设计、流畅的交互体验和丰富的自定义选项,成为Android开发中处理日期时间和多级联动选择的理想解决方案。
核心架构设计
Android-PickerView采用模块化的架构设计,主要分为三个层次:
核心功能特性
1. 时间选择器 (TimePickerView)
时间选择器支持多种时间格式配置,具备以下核心功能:
| 功能特性 | 描述 | 配置方法 |
|---|---|---|
| 时间格式 | 支持年月日时分秒任意组合 | setType(new boolean[]{true, true, true, true, true, true}) |
| 时间范围 | 自定义起始和结束时间 | setRangDate(startDate, endDate) |
| 农历支持 | 支持农历日期显示 | setLunarCalendar(true) |
| 循环模式 | 支持无限循环滚动 | isCyclic(true) |
| 标签定制 | 自定义年月日时分秒标签 | setLabel("年", "月", "日", "时", "分", "秒") |
// 时间选择器配置示例
TimePickerView pvTime = new TimePickerBuilder(this, new OnTimeSelectListener() {
@Override
public void onTimeSelect(Date date, View v) {
// 时间选择回调
Toast.makeText(MainActivity.this, getTime(date), Toast.LENGTH_SHORT).show();
}
})
.setType(new boolean[]{true, true, true, true, false, false}) // 显示年月日时
.setRangDate(startDate, endDate) // 设置时间范围
.isCyclic(true) // 启用循环滚动
.setLabel("年", "月", "日", "时", "", "") // 自定义标签
.build();
2. 选项选择器 (OptionsPickerView)
选项选择器支持多级联动选择,具备以下核心功能:
| 功能特性 | 描述 | 配置方法 |
|---|---|---|
| 多级联动 | 支持1-3级数据联动 | setPicker(options1Items, options2Items, options3Items) |
| 联动控制 | 可禁用联动效果 | setLinkage(false) |
| 数据适配 | 支持多种数据格式 | ArrayWheelAdapter, NumericWheelAdapter |
| 默认选中 | 设置默认选中项 | setSelectOptions(option1, option2, option3) |
| 标签显示 | 自定义各级标签 | setLabels("省", "市", "区") |
// 选项选择器配置示例
OptionsPickerView pvOptions = new OptionsPickerBuilder(this, new OnOptionsSelectListener() {
@Override
public void onOptionsSelect(int options1, int option2, int options3, View v) {
// 选项选择回调
String result = options1Items.get(options1).getPickerViewText()
+ options2Items.get(option2)
+ options3Items.get(options3).getPickerViewText();
tvResult.setText(result);
}
})
.setLinkage(true) // 启用联动
.setLabels("省", "市", "区") // 设置标签
.setSelectOptions(0, 0, 0) // 默认选中第一项
.build();
pvOptions.setPicker(provinceList, cityList, districtList); // 设置三级数据
3. 基础滚轮控件 (WheelView)
WheelView是整个选择器库的基础组件,提供了3D滚轮效果的核心实现:
4. 丰富的自定义选项
Android-PickerView提供了全面的自定义配置选项:
样式配置选项:
- 文字大小和颜色设置
- 分隔线样式和颜色(支持FILL、WRAP、CIRCLE三种类型)
- 背景颜色和透明度渐变
- 可见项目数量控制
- 文字偏移量调整
交互配置选项:
- 对话框模式与嵌入模式切换
- 外部点击是否取消显示
- 按键返回处理
- 动画效果配置
布局配置选项:
- 完全自定义布局支持
- 重力方向设置
- 容器视图定制
性能优化特性
该库在性能方面做了大量优化:
- 高效的重绘机制:采用局部重绘策略,减少不必要的界面刷新
- 平滑的滚动算法:基于物理模型的惯性滚动和减速停止算法
- 内存优化:使用对象池和缓存机制减少内存分配
- 异步处理:耗时操作在后台线程执行,避免阻塞UI线程
扩展功能支持
除了基本功能外,Android-PickerView还提供了一些高级扩展功能:
- 农历日期支持:集成农历转换算法,支持公历农历切换
- 自定义适配器:支持开发者自定义数据适配器
- 国际化支持:提供多语言资源文件
- 夜间模式:支持深色主题配置
- 无障碍访问:遵循Android无障碍设计指南
通过这样全面的功能设计和精心的架构实现,Android-PickerView为Android开发者提供了一个功能强大、性能优异、易于使用的选择器解决方案,能够满足各种复杂的日期时间和选项选择需求。
时间选择器TimePickerView深度解析
Android-PickerView库中的TimePickerView组件是一个功能强大的时间选择控件,它提供了丰富的自定义选项和灵活的配置方式,能够满足各种复杂的时间选择需求。本节将深入解析TimePickerView的核心实现机制、使用方法和高级特性。
核心架构设计
TimePickerView采用了分层架构设计,通过多个组件的协同工作来实现完整的时间选择功能:
时间选择流程分析
TimePickerView的时间选择过程遵循清晰的交互流程:
核心功能特性详解
1. 时间格式灵活配置
TimePickerView支持多种时间格式组合,通过type参数控制显示的时间单位:
// 显示年月日时分秒
new boolean[]{true, true, true, true, true, true}
// 仅显示年月日
new boolean[]{true, true, true, false, false, false}
// 仅显示时分
new boolean[]{false, false, false, true, true, false}
2. 时间范围精确控制
支持设置起始和终止时间,确保用户只能在有效范围内选择:
Calendar startDate = Calendar.getInstance();
startDate.set(2020, 0, 1); // 2020年1月1日
Calendar endDate = Calendar.getInstance();
endDate.set(2030, 11, 31); // 2030年12月31日
TimePickerBuilder builder = new TimePickerBuilder(this, listener)
.setRangDate(startDate, endDate);
3. 农历/公历双模式支持
TimePickerView内置农历支持,可以轻松切换显示模式:
// 启用农历模式
pvTime.setLunarCalendar(true);
// 禁用农历模式(默认公历)
pvTime.setLunarCalendar(false);
4. 丰富的自定义选项
通过PickerOptions可以配置各种显示属性:
| 配置项 | 说明 | 示例值 |
|---|---|---|
| textSizeContent | 文字大小 | 18 |
| textColorCenter | 选中项文字颜色 | Color.BLUE |
| textColorOut | 未选中项文字颜色 | Color.GRAY |
| dividerColor | 分割线颜色 | 0xFFDDDDDD |
| isCyclic | 是否循环滚动 | true |
| isCenterLabel | 是否只显示中间标签 | false |
实现原理深度剖析
滚轮组件联动机制
TimePickerView的核心在于WheelTime类,它负责管理多个WheelView组件之间的联动关系:
public class WheelTime {
private WheelView wv_year;
private WheelView wv_month;
private WheelView wv_day;
// ... 其他时间单位组件
// 设置时间选择变化监听器
private void setChangedListener(WheelView wheelView) {
wheelView.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
if (mSelectChangeCallback != null) {
mSelectChangeCallback.onTimeSelectChanged();
}
}
});
}
}
农历转换算法
农历功能的实现依赖于ChinaDate工具类,它提供了完整的农历转换算法:
public class ChinaDate {
// 阳历转农历
public static int[] solarToLunar(int year, int month, int day) {
// 复杂的农历转换算法实现
}
// 获取农历月份天数
public static int monthDays(int year, int month) {
// 根据年份和月份计算天数
}
// 判断闰月
public static int leapMonth(int year) {
// 闰月判断逻辑
}
}
高级使用技巧
自定义布局集成
TimePickerView支持完全自定义布局,只需确保包含必要的组件ID:
<!-- 自定义布局必须包含的组件 -->
<LinearLayout android:id="@+id/timepicker">
<WheelView android:id="@+id/year"/>
<WheelView android:id="@+id/month"/>
<WheelView android:id="@+id/day"/>
<WheelView android:id="@+id/hour"/>
<WheelView android:id="@+id/min"/>
<WheelView android:id="@+id/second"/>
</LinearLayout>
性能优化建议
- 避免频繁创建实例:TimePickerView初始化开销较大,建议复用实例
- 合理设置时间范围:过大的时间范围会影响性能
- 使用适当的分辨率:根据设备屏幕尺寸调整文字大小和间距
常见问题解决方案
时间范围设置注意事项
// 错误示例:月份从0开始,12表示13月(不存在)
startDate.set(2013, 1, 1); // 实际为2013年2月1日
endDate.set(2020, 12, 1); // 实际为2021年1月1日
// 正确示例:月份范围0-11
startDate.set(2013, 0, 1); // 2013年1月1日
endDate.set(2020, 11, 31); // 2020年12月31日
农历模式下的特殊处理
农历模式下需要注意闰月的情况,WheelTime会自动处理闰月显示:
// 自动处理闰月显示
if (ChinaDate.leapMonth(year) != 0 && month > ChinaDate.leapMonth(year) - 1) {
// 调整月份显示逻辑
}
TimePickerView作为Android-PickerView库的核心组件,通过精心的架构设计和丰富的功能特性,为开发者提供了强大而灵活的时间选择解决方案。无论是简单的日期选择还是复杂的农历支持,都能满足各种应用场景的需求。
选项选择器OptionsPickerView使用指南
OptionsPickerView是Android-PickerView库中功能强大的选项选择器组件,专门用于处理多级联动和非联动的选项选择场景。它提供了丰富的配置选项和灵活的API,能够满足各种复杂的选择需求。
核心特性与架构
OptionsPickerView采用建造者模式设计,通过OptionsPickerBuilder进行配置,支持以下核心特性:
- 多级联动支持:支持1-3级选项联动,可配置是否启用联动
- 灵活的数据源:支持List、List 、List<List >三种数据结构
- 自定义样式:可自定义文字颜色、大小、背景色、分割线样式等
- 循环滚动:支持各级选项的循环滚动配置
- 实时回调:提供选项变化和选择完成的实时监听
基础使用示例
1. 单级选项选择器
// 创建单级选项选择器
OptionsPickerView<String> pvOptions = new OptionsPickerBuilder(this,
new OnOptionsSelectListener() {
@Override
public void onOptionsSelect(int options1, int option2, int options3, View v) {
String selectedItem = optionsItems.get(options1);
Toast.makeText(MainActivity.this, "选中: " + selectedItem, Toast.LENGTH_SHORT).show();
}
})
.setTitleText("请选择")
.setSubmitText("确定")
.setCancelText("取消")
.build();
// 准备数据源
List<String> optionsItems = Arrays.asList("选项1", "选项2", "选项3", "选项4", "选项5");
// 设置数据并显示
pvOptions.setPicker(optionsItems);
pvOptions.show();
2. 二级联动选择器
// 创建二级联动选择器
OptionsPickerView<String> pvOptions = new OptionsPickerBuilder(this,
new OnOptionsSelectListener() {
@Override
public void onOptionsSelect(int options1, int option2, int options3, View v) {
String province = provinceList.get(options1);
String city = cityList.get(options1).get(option2);
String result = province + " - " + city;
tvResult.setText(result);
}
})
.setTitleText("省市选择")
.setLabels("省", "市", "")
.setLinkage(true) // 启用联动
.build();
// 准备二级联动数据
List<String> provinceList = Arrays.asList("北京市", "上海市", "广东省");
List<List<String>> cityList = Arrays.asList(
Arrays.asList("东城区", "西城区", "朝阳区", "丰台区"),
Arrays.asList("黄浦区", "徐汇区", "长宁区", "静安区"),
Arrays.asList("广州市", "深圳市", "东莞市", "佛山市")
);
pvOptions.setPicker(provinceList, cityList);
pvOptions.show();
3. 三级联动选择器(省市区)
// 三级联动选择器配置
OptionsPickerView<JsonBean> pvOptions = new OptionsPickerBuilder(this,
new OnOptionsSelectListener() {
@Override
public void onOptionsSelect(int options1, int option2, int options3, View v) {
JsonBean province = options1Items.get(options1);
JsonBean city = options2Items.get(options1).get(option2);
JsonBean district = options3Items.get(options1).get(option2).get(options3);
String address = province.getPickerViewText() + " " +
city.getPickerViewText() + " " +
district.getPickerViewText();
tvAddress.setText(address);
}
})
.setTitleText("城市选择")
.setLabels("省", "市", "区")
.setContentTextSize(18)
.setLinkage(true)
.build();
// 设置三级联动数据
pvOptions.setPicker(provinceList, cityList, districtList);
pvOptions.setSelectOptions(0, 0, 0); // 设置默认选中项
pvOptions.show();
高级配置选项
OptionsPickerView提供了丰富的配置选项,可以满足各种定制化需求:
样式配置表
| 配置方法 | 说明 | 默认值 |
|---|---|---|
setSubmitText() | 确定按钮文字 | "确定" |
setCancelText() | 取消按钮文字 | "取消" |
setTitleText() | 标题文字 | "" |
setLabels() | 各级标签文字 | "", "", "" |
setSubmitColor() | 确定按钮颜色 | Color.BLUE |
setCancelColor() | 取消按钮颜色 | Color.BLUE |
setTitleColor() | 标题文字颜色 | Color.BLACK |
setBgColor() | 滚轮背景颜色 | 0xFF000000 |
setTitleBgColor() | 标题背景颜色 | 0xFF333333 |
布局与行为配置
OptionsPickerView<String> pvOptions = new OptionsPickerBuilder(this, listener)
.setContentTextSize(20) // 滚轮文字大小
.setTitleSize(22) // 标题文字大小
.setSubCalSize(18) // 按钮文字大小
.setOutSideCancelable(false) // 点击外部是否取消
.isDialog(true) // 是否以对话框形式显示
.setCyclic(false, false, false) // 各级是否循环滚动
.isCenterLabel(true) // 是否只显示中间选中项的label
.setItemVisibleCount(7) // 最大可见项数目
.isAlphaGradient(true) // 透明度渐变效果
.isRestoreItem(true) // 切换时是否还原第一项
.setLineSpacingMultiplier(2.0f) // Item间距倍数
.setDividerColor(Color.GRAY) // 分割线颜色
.setTextColorCenter(Color.RED) // 选中项文字颜色
.setTextColorOut(Color.GRAY) // 非选中项文字颜色
.build();
非联动模式使用
对于不需要联动的场景,可以使用setNPicker方法:
// 非联动模式示例
List<String> departments = Arrays.asList("技术部", "市场部", "财务部");
List<String> positions = Arrays.asList("经理", "主管", "员工");
List<String> levels = Arrays.asList("初级", "中级", "高级");
OptionsPickerView<String> pvOptions = new OptionsPickerBuilder(this,
new OnOptionsSelectListener() {
@Override
public void onOptionsSelect(int options1, int option2, int options3, View v) {
String dept = departments.get(options1);
String pos = positions.get(option2);
String lvl = levels.get(options3);
String result = dept + " - " + pos + " - " + lvl;
tvResult.setText(result);
}
})
.setLinkage(false) // 明确设置为非联动
.setLabels("部门", "职位", "级别")
.build();
pvOptions.setNPicker(departments, positions, levels);
pvOptions.show();
实时监听选项变化
除了选择完成的监听,还可以监听选项的实时变化:
OptionsPickerView<String> pvOptions = new OptionsPickerBuilder(this, selectListener)
.setOptionsSelectChangeListener(new OnOptionsSelectChangeListener() {
@Override
public void onOptionsSelectChanged(int options1, int options2, int options3) {
// 实时获取当前选中的位置
String info = "选项1: " + options1 + ", 选项2: " + options2 + ", 选项3: " + options3;
Log.d("PickerDebug", info);
}
})
.build();
自定义布局实现
OptionsPickerView支持完全自定义布局,只需提供自定义的layout文件:
<!-- res/layout/custom_options_layout.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white">
<RelativeLayout
android:id="@+id/custom_topbar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/primary">
<TextView
android:id="@+id/tv_custom_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@color/white"
android:textSize="18sp"/>
<ImageView
android:id="@+id/iv_custom_close"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="16dp"
android:src="@drawable/ic_close"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/optionspicker"
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="horizontal"/>
</LinearLayout>
// 使用自定义布局
OptionsPickerView<String> pvCustom = new OptionsPickerBuilder(this, selectListener)
.setLayoutRes(R.layout.custom_options_layout, new CustomListener() {
@Override
public void customLayout(View v) {
TextView tvTitle = v.findViewById(R.id.tv_custom_title);
ImageView ivClose = v.findViewById(R.id.iv_custom_close);
tvTitle.setText("自定义选择器");
ivClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pvCustom.dismiss();
}
});
}
})
.build();
数据模型要求
对于联动选择器,数据模型需要实现IPickerViewData接口:
public class ProvinceBean implements IPickerViewData {
private String name;
private List<CityBean> cityList;
@Override
public String getPickerViewText() {
return name;
}
// Getter和Setter方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List<CityBean> getCityList() { return cityList; }
public void setCityList(List<CityBean> cityList) { this.cityList = cityList; }
}
public class CityBean implements IPickerViewData {
private String name;
private List<DistrictBean> districtList;
@Override
public String getPickerViewText() {
return name;
}
// Getter和Setter方法
// ...
}
性能优化建议
- 数据预处理:对于大型数据集,提前处理好数据结构,避免在UI线程进行复杂操作
- 内存管理:及时释放不再使用的选择器实例,避免内存泄漏
- 配置复用:对于相同样式的选择器,可以复用配置对象
- 异步加载:大数据集考虑异步加载和分页显示
// 性能优化示例
public class PickerManager {
private static OptionsPickerBuilder cachedBuilder;
public static OptionsPickerBuilder getCachedBuilder(Context context,
OnOptionsSelectListener listener) {
if (cachedBuilder == null) {
cachedBuilder = new OptionsPickerBuilder(context, listener)
.setSubmitText("确定")
.setCancelText("取消")
.setTitleText("请选择")
.setContentTextSize(18);
}
return cachedBuilder;
}
}
OptionsPickerView提供了强大而灵活的选项选择功能,通过合理的配置和使用,可以满足各种复杂的业务场景需求。掌握其核心API和配置选项,能够显著提升开发效率和用户体验。
三级联动数据配置与实现原理
Android-PickerView的三级联动功能是其核心特性之一,通过精心设计的数据结构和联动机制,实现了类似iOS风格的省市区选择器。本文将深入解析三级联动的数据配置方式和实现原理。
数据结构设计
三级联动功能依赖于特定的数据结构设计,支持两种主要的数据格式:
1. 嵌套列表数据结构
// 三级联动数据结构示例
List<T> options1Items; // 第一级数据(省份)
List<List<T>> options2Items; // 第二级数据(城市),每个省份对应一个城市列表
List<List<List<T>>> options3Items; // 第三级数据(区域),每个城市对应一个区域列表
这种数据结构通过三层嵌套的List来实现层级关系,确保数据的完整性和一致性。
2. JSON数据结构
项目提供了标准的JSON数据格式,便于从网络或本地文件加载省市区数据:
[
{
"name": "北京市",
"city": [
{
"name": "北京市",
"area": ["东城区", "西城区", "朝阳区", "丰台区", "石景山区", "海淀区"]
}
]
},
{
"name": "天津市",
"city": [
{
"name": "天津市",
"area": ["和平区", "河东区", "河西区", "南开区", "河北区", "红桥区"]
}
]
}
]
数据实体类设计
为了实现数据的灵活处理,项目定义了专门的实体类:
// JsonBean实体类
public class JsonBean implements IPickerViewData {
private String name;
private List<CityBean> city;
@Override
public String getPickerViewText() {
return this.name;
}
// getter和setter方法
}
// CityBean内部类
public class CityBean {
private String name;
private List<String> area;
// getter和setter方法
}
联动机制实现原理
三级联动的核心在于WheelOptions类,它负责管理三个级别的WheelView并处理它们之间的联动关系。
联动监听器设计
// 第一级选项监听器
wheelListener_option1 = new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
// 更新第二级数据
wv_option2.setAdapter(new ArrayWheelAdapter(mOptions2Items.get(index)));
// 触发第三级更新
wheelListener_option2.onItemSelected(wv_option2.getCurrentItem());
}
};
// 第二级选项监听器
wheelListener_option2 = new OnItemSelectedListener() {
@Override
public void onItemSelected(int index) {
// 更新第三级数据
wv_option3.setAdapter(new ArrayWheelAdapter(
mOptions3Items.get(wv_option1.getCurrentItem()).get(index)));
}
};
数据初始化流程
关键配置参数
三级联动支持多种配置选项,满足不同的业务需求:
| 配置参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
linkage | boolean | true | 是否启用联动效果 |
isRestoreItem | boolean | false | 切换时是否还原到第一项 |
cyclic | boolean[] | [false,false,false] | 各级是否循环滚动 |
labels | String[] | null | 各级的单位标签 |
数据加载与解析
从JSON文件加载数据的完整流程:
public ArrayList<JsonBean> parseData(String jsonResult) {
ArrayList<JsonBean> detail = new ArrayList<>();
try {
JSONArray data = new JSONArray(jsonResult);
Gson gson = new Gson();
for (int i = 0; i < data.length(); i++) {
JsonBean entity = gson.fromJson(data.optJSONObject(i).toString(), JsonBean.class);
detail.add(entity);
}
} catch (Exception e) {
e.printStackTrace();
}
return detail;
}
性能优化策略
为了提高三级联动的性能,项目采用了以下优化措施:
- 懒加载机制:只有在需要时才加载下一级数据
- 数据缓存:已加载的数据进行缓存,避免重复解析
- 视图复用:WheelView组件复用,减少内存占用
- 异步处理:大数据量时采用异步加载方式
自定义数据适配
开发者可以轻松扩展支持自定义数据类型:
// 实现IPickerViewData接口
public class CustomData implements IPickerViewData {
private String displayName;
private Object additionalData;
@Override
public String getPickerViewText() {
return displayName;
}
}
// 使用自定义适配器
wv_option1.setAdapter(new ArrayWheelAdapter<>(customDataList));
异常处理机制
为确保联动的稳定性,实现了完善的异常处理:
// 数据越界保护
int opt2Select = wv_option2.getCurrentItem();
opt2Select = opt2Select >= mOptions2Items.get(index).size() - 1 ?
mOptions2Items.get(index).size() - 1 : opt2Select;
// 空数据检查
if (mOptions2Items == null) {
wv_option2.setVisibility(View.GONE);
} else {
wv_option2.setVisibility(View.VISIBLE);
}
通过这种精心设计的数据结构和联动机制,Android-PickerView实现了高效、稳定的三级联动功能,为开发者提供了便捷的省市区选择解决方案。
总结
Android-PickerView通过精心设计的数据结构和联动机制,实现了高效、稳定的三级联动功能,为开发者提供了便捷的省市区选择解决方案。该库采用模块化的架构设计,支持多种时间格式配置、多级联动选择、丰富的自定义选项和全面的性能优化,能够满足各种复杂的日期时间和选项选择需求。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



