需求:实现一年月日选择器,默认为当前日期,三者联动,并且在切换年月时,根据是否闰年或者月份天数动态改变日。多说无益,请看下图:
使用的第三方库(/helloJp/WheelView)
此库可兼容到低版本,定制性很强,获取选中数据很方便。详情请戳链接,感谢helloJp的分享。
activity_main.xml放置一个封装好WheelView的自定义控件,没有什么自定义属性
<RelativeLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><.datepicker.DatePickerandroid:id="@+id/birthday_picker"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:layout_margin="5dp"android:gravity="center_horizontal" /></RelativeLayout>
date_picker.xml线性布局放置三个WheelView,分别对应年月日:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/rectangle_bg"android:padding="2dp"android:gravity="center_vertical"android:orientation="horizontal"><.datepicker.WheelView android:id="@+id/year"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:itemNumber="5"app:lineColor="@android:color/darker_gray"app:lineHeight="2dp"app:maskHight="32dp"app:noEmpty="true"app:normalTextColor="@color/material_green_300"app:normalTextSize="14sp"app:selectedTextColor="@color/material_light_blue_a700"app:selectedTextSize="22sp"app:unitHight="50dp"/><.datepicker.WheelView android:id="@+id/month"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:itemNumber="5"app:lineColor="@android:color/darker_gray"app:lineHeight="2dp"app:maskHight="32dp"app:noEmpty="true"app:normalTextColor="@color/material_light_blue_a100"app:normalTextSize="14sp"app:selectedTextColor="@color/material_red_300"app:selectedTextSize="22sp"app:unitHight="50dp"/><.datepicker.WheelView android:id="@+id/day"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"app:itemNumber="5"app:lineColor="@android:color/darker_gray"app:lineHeight="2dp"app:maskHight="32dp"app:noEmpty="true"app:normalTextColor="@color/material_orange_500"app:normalTextSize="14sp"app:selectedTextColor="@color/material_deep_purple_300"app:selectedTextSize="22sp"app:unitHight="50dp"/></LinearLayout>
自定义属性如下,定制性相当强:
AttributesThere are several attributes you can set:attr 属性 description 描述lineColor divider line color 分割线颜色lineHeight divider line height 分割线高度itemNumber wheelview show item count 此wheelView显示item的个数maskHight mask height 蒙版高度(normalText的位置)noEmpty if set true select area can't be null(empty),or could be empty 设置true则选中不能为空,否则可以是空normalTextColor unSelected Text color 未选中文本颜色normalTextSize unSelected Text size 未选中文本字体大小selectedTextColor selected Text color 选中文本颜色selectedTextSize selected Text size 选中文本字体大小unitHight item unit height 每个item单元的高度
主要看下DatePicker 代码是如何实现联动的:
public class DatePicker extends LinearLayout implements WheelView.OnSelectListener {public DatePicker(Context context) {this(context, null);}public DatePicker(Context context, AttributeSet attrs) {super(context, attrs);}/*** 获取选择的年** @return*/public String getYear() {return mWheelYear.getSelectedText();}/*** 获取选择的月** @return*/public String getMonth() {return mWheelMonth.getSelectedText();}/*** 获取选择的日** @return*/public String getDay() {return mWheelDay.getSelectedText();}private WheelView mWheelYear;private WheelView mWheelMonth;private WheelView mWheelDay;@Overrideprotected void onFinishInflate() {super.onFinishInflate();LayoutInflater.from(getContext()).inflate(R.layout.date_picker, this);mWheelYear = (WheelView) findViewById(R.id.year);mWheelMonth = (WheelView) findViewById(R.id.month);mWheelDay = (WheelView) findViewById(R.id.day);// 格式化当前时间,并转换为年月日整型数据SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());String[] split = sdf.format(new Date()).split("-");int currentYear = Integer.parseInt(split[0]);int currentMonth = Integer.parseInt(split[1]);int currentDay = Integer.parseInt(split[2]);// 设置默认年月日为当前日期mWheelYear.setData(getYearData(currentYear));mWheelYear.setDefault(0);mWheelMonth.setData(getMonthData());mWheelMonth.setDefault(currentMonth - 1);mWheelDay.setData(getDayData(getLastDay(currentYear, currentMonth)));mWheelDay.setDefault(currentDay - 1);mWheelYear.setOnSelectListener(this);mWheelMonth.setOnSelectListener(this);mWheelDay.setOnSelectListener(this);}/*** 年范围在:1900~今年** @param currentYear* @return*/private ArrayList<String> getYearData(int currentYear) {ArrayList<String> list = new ArrayList<>();for (int i = currentYear; i >= 1900; i--) {list.add(String.valueOf(i));}return list;}private ArrayList<String> getMonthData() {ArrayList<String> list = new ArrayList<>();for (int i = 1; i <= 12; i++) {list.add(String.valueOf(i));}return list;}/*** 日范围在1~lastDay** @param lastDay* @return*/private ArrayList<String> getDayData(int lastDay) {//ignore conditionArrayList<String> list = new ArrayList<>();for (int i = 1; i <= lastDay; i++) {list.add(String.valueOf(i));}return list;}/*** 判断是否闰年** @param year* @return*/private boolean isLeapYear(int year) {return (year % 100 == 0 && year % 400 == 0) || (year % 100 != 0 && year % 4 == 0);}/*** 获取特定年月对应的天数** @param year* @param month* @return*/private int getLastDay(int year, int month) {if (month == 2) {// 2月闰年的话返回29,防止28return isLeapYear(year) ? 29 : 28;}// 一三五七八十腊,三十一天永不差return month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 ? 31 : 30;}@Overridepublic void endSelect(View view, int id, String text) {// 滚轮滑动停止后调用switch (view.getId()) {case R.id.year:case R.id.month:// 记录当前选择的天数int selectDay = Integer.parseInt(getDay());// 根据当前选择的年月获取对应的天数int lastDay = getLastDay(Integer.parseInt(getYear()), Integer.parseInt(getMonth()));// 设置天数mWheelDay.setData(getDayData(lastDay));// 如果选中的天数大于实际天数,那么将默认天数设为实际天数;否则还是设置默认天数为选中的天数if (selectDay > lastDay) {mWheelDay.setDefault(lastDay - 1);} else {mWheelDay.setDefault(selectDay - 1);}break;}}@Overridepublic void selecting(View view, int id, String text) {}}
DatePicker继承于线性布局,在onFinishInflate填充date_picker.xml布局,然后拿到三个wheelview,格式化时间,取出年月日。
WheelView的方法:
Method1. setData(ArrayList data)set WheelView data设置WheelView的数据2. resetData(ArrayList data)reset WheelView data ,if you has setData重置 WheelView的数据,如果已经设置过的话3. int getSelected()get selected item index获取选中项的index4. String getSelectedText()get selected item text获取选中项的文本信息5. boolean isScrollingis WheelView is scrolling获取WheelView是否在滚动中6. boolean isEnable()is WheelView is enable获取wheelView是否可用7. void setEnable(boolean isEnable)set WheelView enable设置WheelView是否可用8. void setDefault(int index)set default selected index设置默认选中项的index9. int getListSize()get WheelView item count获取WheelView的item项个数10. String getItemText(int index)get the text by index 获取index位置上的文本数据11. void setOnSelectListener(OnSelectListener onSelectListener)set listener on WheelView that can get info when WheelView is scrolling or stop scroll.对WheelView设置监听,在 滑动过程 或者 滑动停止 返回数据信息。
年的话是以当前年作为最开始选中的,因为我实际用来做生日选择器的;月就是12个月没什么好说的。
mWheelYear.setData(getYearData(currentYear));private ArrayList<String> getYearData(int currentYear) {ArrayList<String> list = new ArrayList<>();for (int i = currentYear; i >= 1900; i--) {list.add(String.valueOf(i));}return list;}
日的话稍微复杂点,因为月份不同日数不同,闰年二月天数多一天,所以做多判断。
getLastDay(currentYear, currentMonth)就是根据年月算出日数
mWheelDay.setData(getDayData(getLastDay(currentYear, currentMonth)));private ArrayList<String> getDayData(int lastDay) {//ignore conditionArrayList<String> list = new ArrayList<>();for (int i = 1; i <= lastDay; i++) {list.add(String.valueOf(i));}return list;}private int getLastDay(int year, int month) {if (month == 2) {// 2月闰年的话返回29,防止28return isLeapYear(year) ? 29 : 28;}// 一三五七八十腊,三十一天永不差return month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 ? 31 : 30;}private boolean isLeapYear(int year) {return (year % 100 == 0 && year % 400 == 0) || (year % 100 != 0 && year % 4 == 0);}
我们要联动的话就需要监听三个WheelView的滚动停止对应的数据了,WheelView提供setOnSelectListener给我们监听,这里只需在停止的时候拿到数据做联动即可。
为了直观一点,我们选中的天数会根据年月的不同计算出的实际天数做对比,若选中的天数大于实际天数,会回退到实际天数。
@Overridepublic void endSelect(View view, int id, String text) {// 滚轮滑动停止后调用switch (view.getId()) {case R.id.year:case R.id.month:// 记录当前选择的天数int selectDay = Integer.parseInt(getDay());// 根据当前选择的年月获取对应的天数int lastDay = getLastDay(Integer.parseInt(getYear()), Integer.parseInt(getMonth()));// 设置天数mWheelDay.setData(getDayData(lastDay));// 如果选中的天数大于实际天数,那么将默认天数设为实际天数;否则还是设置默认天数为选中的天数if (selectDay > lastDay) {mWheelDay.setDefault(lastDay - 1);} else {mWheelDay.setDefault(selectDay - 1);}break;}}
实在是简单实用,比官方的好用何止一丢丢。
Demo下载链接如下:
/detail/oushangfeng123/9034101
如果觉得《使用第三方WheelView制作日期选择器》对你有帮助,请点赞、收藏,并留下你的观点哦!