自定义个性的DatePicker
来源:互联网 发布:东欧剧变时的中国知乎 编辑:程序博客网 时间:2024/04/29 05:19
ps: 前段时间遇到一个需求,需可以选月份和号数切换且年份不循环的时间选择器。
解决方式:采用NumberPicker自定义个性的DatePicker
先从官网看下 NumberPicker的属性:https://developer.android.com/reference/android/widget/NumberPicker.html
NumberPicker的api: setFormatter(NumberPicker.Formatter formatter):设置内容的格式 setMaxValue(int maxValue):设置最大值 setMinValue(int minValue):设置最小值 setValue(int value): 根据索引来显示内容 setWrapSelectorWheel(boolean wrapSelectorWheel):设置是否在循环 setOnScrollListener(NumberPicker.OnScrollListener onScrollListener):设置滚动的监听器 setOnValueChangedListener(NumberPicker.OnValueChangeListener onValueChangedListener): 设置内容改变的监控器注意点: 1.maxValues=内容长度-1 2.若是maxValues发生改变,setWrapSelectorWheel()需要重新设置
为什么maxValues=内容长度-1,源码给了答案:
开始动手啦!
(一)自定义NumberPicker:改变字体颜色
CustormNumberPicker.java:
public class CustormNumberPicker extends NumberPicker { public CustormNumberPicker(Context context, AttributeSet attrs) { super(context, attrs); } public CustormNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs,defStyleAttr); } @Override public void addView(View child) { super.addView(child); updateView(child); } @Override public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) { super.addView(child, index, params); updateView(child); } @Override public void addView(View child, android.view.ViewGroup.LayoutParams params) { super.addView(child, params); updateView(child); } public void updateView(View view) { if (view instanceof EditText) { //这里修改字体的属性 ((EditText) view).setTextColor(Color.parseColor("#e68f17")); } }}
(二)改变NumberPicker的间隔线颜色,关闭editext的光标:
官方没有提供改变NumberPicker的分割线颜色的api,这里就采用反射来突破Private私有化。(ps:从网上找到的解决方式)
public void setNumberPickerCong(NumberPicker picker, int maxValues, String[] values, int currentPosition) { picker.setMinValue(0); picker.setMaxValue(maxValues); if(picker.getId()==R.id.selectdate_dialog_year){//年份不循环 picker.setWrapSelectorWheel(false); } picker.setDisplayedValues(values); picker.setValue(currentPosition); picker.setOnValueChangedListener(this); //反射设置分割线颜色: Field[] pickerFields = NumberPicker.class.getDeclaredFields(); for (Field f : pickerFields) { if (f.getName().equals("mSelectionDivider")) { f.setAccessible(true); try { //设置需求的颜色 f.set(picker, new ColorDrawable(context.getResources().getColor( R.color.gasstation_selectdate_gray))); } catch (Exception e) { e.printStackTrace(); } break; } } //反射设置分割线高度: for (Field f : pickerFields) { if (f.getName().equals("mSelectionDividerHeight")) { f.setAccessible(true); try { f.set(picker, 1); } catch (Exception e) { e.printStackTrace(); } break; } } //关掉编辑模式 picker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); }
(三)计算每年每个月的最大天数:
Calendar可以获取当前年,月,分。还可以获取某年某月中的最大天数代码如下:
private Calendar calendar; /** * 获取当前的年,月,号,当前月最大号数 */ public void getCurrentDate() { calendar= Calendar.getInstance(Locale.getDefault()); currentYear = calendar.get(Calendar.YEAR); currentMonth = calendar.get(Calendar.MONTH); currentDay = calendar.get(Calendar.DAY_OF_MONTH); currentMaxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); } /** * 计算某月最大天数 * @param year * @param month * @return */ public int getMaxDay(int year, int month) { calendar.clear();//清空默认时间 calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month - 1);// Calendar中,月份从0开始算起 int day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); return day; }
(四)初始化年,月,天的数据:
这里采用四个数组来装天数(28,29,30,31),一个数组来装月的数据(1,2….,12),一个数组装年
private String[] years, months, days; private List<String> dayList; private String[] day_28, day_29, day_30, day_31; private void initData() { dayList = new ArrayList<>(); years = new String[5]; months = new String[12]; //初始化,月份的数据,四种天数的数据(28,29,30,31) for (int i = 1; i < 32; i++) { int position = i - 1; String content = String.valueOf(i); setYearCong(position); setMonthCong(position,content); dayList.add(content); setDayCong(i,dayList); } recycleList(); } /** * 设置当前年份的前后两年,比如2014,2015,2016,2017,2018 * @param position */ public void setYearCong(int position){ if(position<5){ years[position]=String.valueOf((currentYear+2)-4+position); } } /** * 设置月份,1~12 * @param position * @param month */ public void setMonthCong(int position,String month){ if (position < 12) { months[position] = month; } } /** * 设置天数四个数组,(28,29,30,31) * @param index * @param dayList */ public void setDayCong(int index,List<String> dayList){ switch (index){ case 28: day_28= new String[28]; listCopyArray(dayList, day_28); break; case 29: day_29= new String[29]; listCopyArray(dayList, day_29); break; case 30: day_30= new String[30]; listCopyArray(dayList, day_30); break; case 31: day_31= new String[31]; listCopyArray(dayList, day_31); break; } } /** * 回收list */ private void recycleList() { if(dayList!=null){ dayList.clear(); dayList=null; } }
(五)监控滑动年或者月的选中状态改变时,这个月中的最大天数也随着改变:
在NumberPicker的setOnValueChangedListener()中监控滑动导致值改变:
/** * 监控NumberPicker 的滑动值改变: * 当年份或者月份改变时,每个月的最大天数必须随着改变 * @param picker * @param oldVal * @param newVal */ @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { switch (picker.getId()) { case R.id.selectdate_dialog_year: currentMaxDay=getMaxDay(Integer.valueOf(years[newVal]), Integer.valueOf( months[month_NumberPicker.getValue()] ) ); setDay_NnmberPicekerCong(currentMaxDay); break; case R.id.selectdate_dialog_month: currentMaxDay=getMaxDay(Integer.valueOf( years[year_NumberPicker.getValue() ]), Integer.valueOf( months[ newVal ] )); setDay_NnmberPicekerCong(currentMaxDay); break; } } /** * 根据每个月最大天数,来设置显示day的NumberPicker * @param index */ public void setDay_NnmberPicekerCong(int index) { switch (index) { case 28: days = day_28; break; case 29: days = day_29; break; case 30: days = day_30; break; case 31: days = day_31; break; } if(isFirt){ //设置当前的号数,即今天是几号 setNumberPickerCong(day_NnmberPiceker, days.length - 1, days, currentDay - 1); isFirt=false; } else{ //滑动年,月导致最大号数的改变(即28或者29或者30或者31) int before_Size= day_NnmberPiceker.getMaxValue()+1; if(before_Size<=(days.length-1)){//原本的length< 即将设置max(特殊情况:b_length=m_max) day_NnmberPiceker.setDisplayedValues(days); day_NnmberPiceker.setMaxValue(days.length-1); day_NnmberPiceker.setMinValue(0); }else{ //(原本的max+1)>=即将设置的length day_NnmberPiceker.setMinValue(0); day_NnmberPiceker.setMaxValue(days.length-1); day_NnmberPiceker.setDisplayedValues(days); } } }
在更新NumberPicker的时候遇到一个很奇特的问题,拿出来分享下:
操作 length maxValues curent 30 29 update 31 30 先设置setMaxValues(),再设置setDisplayedValues() 运行结果却报异常: error: java.lang.ArrayIndexOutOfBoundsException: length=30; index=30
截图如下:
经过多次尝试,总结规律:原本的maxValues>=即将设置的maxValues,那先设置setMax,再设置content.反之,先设置content,在来设置max
ps:将三个numberPicker(年,月,天)封装在Dialog中,对外提供选择时间的方法,在下载的项目中都有,偷懒不写了
经历一番波折,填坑,最终完成需求,展示成果:
项目下载:http://download.csdn.net/detail/hexingen/9590302
- 自定义个性的DatePicker
- 自定义的DatePicker
- 自定义datePicker的实现
- 自定义包含DatePicker的AlertDialog
- excel||单元格自定义,个性的追求
- 自定义dialog 满足各种个性的需求
- 【Android自定义View】美观个性的进度条
- Android一个个性的自定义progressbar
- Android 自定义带两个DatePicker的DatePickerDialog
- 自定义个性cmd界面 轻松打造个性的cmd 修改cmd字体颜色 添加个性cmd内容(转)
- 类似Google个性首页的页面自定义拖拽布局
- 类似Google个性首页的页面自定义拖拽布局
- 类似Google个性首页的页面自定义拖拽布局
- Android 自定义DatePicker / DatePickerDialog
- Android中自定义DatePicker
- 自定义时间选择器DatePicker
- datepicker自定义显示年月日
- DatePicker(日期选择自定义服务器控件)的实现
- performClick()方法的使用
- 正则表达式
- Ubuntu系统安装搜狗输入法
- 1099. Build A Binary Search Tree (30)
- NYOJ-722-数独
- 自定义个性的DatePicker
- C++的try_catch异常
- canvas 3D 正方形
- final关键字
- 手把手教你<leetcode>中的回溯算法——多一点套路
- juery datatable属性描述以及用法
- 1. 《深入理解Java虚拟机》Java运行时数据区域
- 某个小泥塑课
- bdev文件系统