在开发中如果有地址或者日期选择等就会涉及到时间或者条件选择器,大家都会想到仿ios的三级联动的效果,用wheelview实现,其实安卓原生自带了时间和日期选择器可能是效果来说太粗犷了,所以很多产品效果图都是清一色的ios那种效果,ok,废话说完了上图
demo地址:https://github.com/PangHaHa12138/TimePackdemo1,安卓原生的时间和日期选择器
代码:
DatePickerDialog dialog = new DatePickerDialog(MainActivity.this, new DatePickerDialog.OnDateSetListener() { @Override public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { if(monthOfYear<=9){ mouth1="0"+(monthOfYear+1); }else{ mouth1=String.valueOf(monthOfYear+1); } if(dayOfMonth<=9){ day1= "0"+dayOfMonth; }else{ day1=String.valueOf(dayOfMonth); } dateStr = String.valueOf(year)+"-"+mouth1+"-"+day1; button1.setText(dateStr); } }, calender.get(Calendar.YEAR), calender.get(Calendar.MONTH), calender.get(Calendar.DAY_OF_MONTH)); dialog.show();使用非常简单,自己写个时间过滤方法就行
TimePickerDialog dialog = new TimePickerDialog(MainActivity.this, new TimePickerDialog.OnTimeSetListener() { @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) { button2.setText(String.valueOf(hourOfDay+":"+minute)); } },calender2.get(Calendar.HOUR),calender2.get(Calendar.MINUTE),false); dialog.show();DatePickerDialog和TimePickerDialog都是原生带的,在5.0之前还是和ios那种效果差不多,来回上下滑选择日期的,但是5.0后就成日历了,虽然好看,不过占比屏太大,设计并不会考虑这种效果,哎,现在很多安卓的控件原生其实效果不错的,不过还是得为了遵循产品和设计的意思做成仿ios效果(小小的抱怨一下)
2.开源日期选择器Timepickview和条件选择器Optionspickview
代码:timepick:
TimePickerView pvTime = new TimePickerView.Builder(MainActivity.this, new TimePickerView.OnTimeSelectListener() { @Override public void onTimeSelect(Date date2, View v) {//选中事件回调 String time = getTime(date2); button3.setText(time); } }) .setType(TimePickerView.Type.YEAR_MONTH_DAY)//默认全部显示 .setCancelText("取消")//取消按钮文字 .setSubmitText("确定")//确认按钮文字 .setContentSize(20)//滚轮文字大小 .setTitleSize(20)//标题文字大小 // .setTitleText("请选择时间")//标题文字 .setOutSideCancelable(true)//点击屏幕,点在控件外部范围时,是否取消显示 .isCyclic(true)//是否循环滚动 .setTextColorCenter(Color.BLACK)//设置选中项的颜色 .setTitleColor(Color.BLACK)//标题文字颜色 .setSubmitColor(Color.BLUE)//确定按钮文字颜色 .setCancelColor(Color.BLUE)//取消按钮文字颜色 // .setTitleBgColor(0xFF666666)//标题背景颜色 Night mode // .setBgColor(0xFF333333)//滚轮背景颜色 Night mode // .setRange(calendar.get(Calendar.YEAR) - 20, calendar.get(Calendar.YEAR) + 20)//默认是1900-2100年 // .setDate(selectedDate)// 如果不设置的话,默认是系统时间*/ // .setRangDate(startDate,endDate)//起始终止年月日设定 // .setLabel("年","月","日","时","分","秒") .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。 // .isDialog(true)//是否显示为对话框样式 .build(); pvTime.setDate(Calendar.getInstance());//注:根据需求来决定是否使用该方法(一般是精确到秒的情况),此项可以在弹出选择器的时候重新设置当前时间,避免在初始化之后由于时间已经设定,导致选中时间与当前时间不匹配的问题。 pvTime.show();注释已经写的很详细了,各种选项干嘛用的
Optionspickview:代码:
options1Items.clear(); options1Items.add("托儿索"); options1Items.add("儿童劫"); options1Items.add("小学生之手"); options1Items.add("德玛西亚大保健"); options1Items.add("面对疾风吧"); options1Items.add("天王盖地虎"); options1Items.add("我发一米五"); options1Items.add("爆刘继芬");
OptionsPickerView pvOptions = new OptionsPickerView.Builder(MainActivity.this, new OptionsPickerView.OnOptionsSelectListener() { @Override public void onOptionsSelect(int options1, int option2, int options3 ,View v) { //返回的分别是三个级别的选中位置 String s = options1Items.get(options1); button4.setText(s); } }) // .setSubmitText("确定")//确定按钮文字 // .setCancelText("取消")//取消按钮文字 // .setTitleText("城市选择")//标题 .setSubCalSize(20)//确定和取消文字大小 // .setTitleSize(20)//标题文字大小 // .setTitleColor(Color.BLACK)//标题文字颜色 .setSubmitColor(Color.BLUE)//确定按钮文字颜色 .setCancelColor(Color.BLUE)//取消按钮文字颜色 // .setTitleBgColor(0xFF333333)//标题背景颜色 Night mode // .setBgColor(0xFF000000)//滚轮背景颜色 Night mode // .setContentTextSize(18)//滚轮文字大小 // .setTextColorCenter(Color.BLUE)//设置选中项的颜色 .setTextColorCenter(Color.BLACK)//设置选中项的颜色 // .setLineSpacingMultiplier(1.6f)//设置两横线之间的间隔倍数 // .setLinkage(false)//设置是否联动,默认true // .setLabels("省", "市", "区")//设置选择的三级单位 // .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。 // .setCyclic(false, false, false)//循环与否 // .setSelectOptions(1, 1, 1) //设置默认选中项 // .setOutSideCancelable(false)//点击外部dismiss default true // .isDialog(true)//是否显示为对话框样式 .build(); pvOptions.setPicker(options1Items); pvOptions.show();条件自己定义,可以传简单集合,也可以传别的,比如省市县...
3.结合wheelview和原生timepick自定义时间选择器
用法:
final String[] str = new String[10]; ChangeDatePopwindow mChangeBirthDialog = new ChangeDatePopwindow(MainActivity.this); mChangeBirthDialog.setDate("2017", "6", "20"); mChangeBirthDialog.showAtLocation(main, Gravity.BOTTOM, 0, 0); mChangeBirthDialog.setBirthdayListener(new ChangeDatePopwindow.OnBirthListener() { @Override public void onClick(String year, String month, String day) { // TODO Auto-generated method stub Toast.makeText(MainActivity.this,year + "-" + month + "-" + day,Toast.LENGTH_LONG).show(); StringBuilder sb = new StringBuilder(); sb.append(year.substring(0, year.length() - 1)).append("-").append(month.substring(0, day.length() - 1)).append("-").append(day); str[0] = year + "-" + month + "-" + day; str[1] = sb.toString(); button5.setText(str[0]); } });大致思路:
年-月-日,其实是三个wheelview,然后手动设置时间的范围,继承原有的adapter
一个例子
* Abstract wheel adapter provides common functionality for adapters. */ public abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter { /** Text view resource. Used as a default view for adapter. */ public static final int TEXT_VIEW_ITEM_RESOURCE = -1; /** No resource constant. */ protected static final int NO_RESOURCE = 0; /** Default text color */ public static final int DEFAULT_TEXT_COLOR = 0xFF585858; /** Default text color */ public static final int LABEL_COLOR = 0xFF700070; /** Default text size */ public static final int DEFAULT_TEXT_SIZE = 18; // Text settings private int textColor = DEFAULT_TEXT_COLOR; private int textSize = DEFAULT_TEXT_SIZE; // Current context protected Context context; // Layout inflater protected LayoutInflater inflater; // Items resources protected int itemResourceId; protected int itemTextResourceId; // Empty items resources protected int emptyItemResourceId; /** * Constructor * @param context the current context */ protected AbstractWheelTextAdapter(Context context) { this(context, TEXT_VIEW_ITEM_RESOURCE); } /** * Constructor * @param context the current context * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views */ protected AbstractWheelTextAdapter(Context context, int itemResource) { this(context, itemResource, NO_RESOURCE); } /** * Constructor * @param context the current context * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views * @param itemTextResource the resource ID for a text view in the item layout */ protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) { this.context = context; itemResourceId = itemResource; itemTextResourceId = itemTextResource; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } /** * Gets text color * @return the text color */ public int getTextColor() { return textColor; } /** * Sets text color * @param textColor the text color to set */ public void setTextColor(int textColor) { this.textColor = textColor; } /** * Gets text size * @return the text size */ public int getTextSize() { return textSize; } /** * Sets text size * @param textSize the text size to set */ public void setTextSize(int textSize) { this.textSize = textSize; } /** * Gets resource Id for items views * @return the item resource Id */ public int getItemResource() { return itemResourceId; } /** * Sets resource Id for items views * @param itemResourceId the resource Id to set */ public void setItemResource(int itemResourceId) { this.itemResourceId = itemResourceId; } /** * Gets resource Id for text view in item layout * @return the item text resource Id */ public int getItemTextResource() { return itemTextResourceId; } /** * Sets resource Id for text view in item layout * @param itemTextResourceId the item text resource Id to set */ public void setItemTextResource(int itemTextResourceId) { this.itemTextResourceId = itemTextResourceId; } /** * Gets resource Id for empty items views * @return the empty item resource Id */ public int getEmptyItemResource() { return emptyItemResourceId; } /** * Sets resource Id for empty items views * @param emptyItemResourceId the empty item resource Id to set */ public void setEmptyItemResource(int emptyItemResourceId) { this.emptyItemResourceId = emptyItemResourceId; } /** * Returns text for specified item * @param index the item index * @return the text of specified items */ protected abstract CharSequence getItemText(int index); @Override public View getItem(int index, View convertView, ViewGroup parent) { if (index >= 0 && index < getItemsCount()) { if (convertView == null) { convertView = getView(itemResourceId, parent); } TextView textView = getTextView(convertView, itemTextResourceId); if (textView != null) { CharSequence text = getItemText(index); if (text == null) { text = ""; } textView.setText(text); if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) { configureTextView(textView); } } return convertView; } return null; } @Override public View getEmptyItem(View convertView, ViewGroup parent) { if (convertView == null) { convertView = getView(emptyItemResourceId, parent); } if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) { configureTextView((TextView)convertView); } return convertView; } /** * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views. * @param view the text view to be configured */ protected void configureTextView(TextView view) { view.setTextColor(textColor); view.setGravity(Gravity.CENTER); view.setTextSize(textSize); view.setEllipsize(TextUtils.TruncateAt.END); view.setLines(1); // view.setCompoundDrawablePadding(20); // view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD); } /** * Loads a text view from view * @param view the text view or layout containing it * @param textResource the text resource Id in layout * @return the loaded text view */ public TextView getTextView(View view, int textResource) { TextView text = null; try { if (textResource == NO_RESOURCE && view instanceof TextView) { text = (TextView) view; } else if (textResource != NO_RESOURCE) { text = (TextView) view.findViewById(textResource); } } catch (ClassCastException e) { Log.e("AbstractWheelAdapter", "You must supply a resource ID for a TextView"); throw new IllegalStateException( "AbstractWheelAdapter requires the resource ID to be a TextView", e); } return text; } /** * Loads view from resources * @param resource the resource Id * @return the loaded view or null if resource is not set */ public View getView(int resource, ViewGroup parent) { switch (resource) { case NO_RESOURCE: return null; case TEXT_VIEW_ITEM_RESOURCE: return new TextView(context); default: return inflater.inflate(resource, parent, false); } }
还有设置滑动监听,改变日期
wvYear.addChangingListener(new OnWheelChangedListener() { @Override public void onChanged(WheelView wheel, int oldValue, int newValue) { // TODO Auto-generated method stub String currentText = (String) mYearAdapter.getItemText(wheel.getCurrentItem()); selectYear = currentText; setTextviewSize(currentText, mYearAdapter); currentYear = currentText.substring(0, currentText.length()-1).toString(); Log.d("currentYear==",currentYear); setYear(currentYear); initMonths(Integer.parseInt(month)); mMonthAdapter = new CalendarTextAdapter(context, arry_months, 0, maxTextSize, minTextSize); wvMonth.setVisibleItems(5); wvMonth.setViewAdapter(mMonthAdapter); wvMonth.setCurrentItem(0); calDays(currentYear, month); } }); wvYear.addScrollingListener(new OnWheelScrollListener() { @Override public void onScrollingStarted(WheelView wheel) { // TODO Auto-generated method stub } @Override public void onScrollingFinished(WheelView wheel) { // TODO Auto-generated method stub String currentText = (String) mYearAdapter.getItemText(wheel.getCurrentItem()); setTextviewSize(currentText, mYearAdapter); } }); wvMonth.addChangingListener(new OnWheelChangedListener() { @Override public void onChanged(WheelView wheel, int oldValue, int newValue) { // TODO Auto-generated method stub String currentText = (String) mMonthAdapter.getItemText(wheel.getCurrentItem()); selectMonth = currentText; setTextviewSize(currentText, mMonthAdapter); setMonth(currentText.substring(0, 1)); initDays(Integer.parseInt(day)); mDaydapter = new CalendarTextAdapter(context, arry_days, 0, maxTextSize, minTextSize); wvDay.setVisibleItems(5); wvDay.setViewAdapter(mDaydapter); wvDay.setCurrentItem(0); calDays(currentYear, month); } }); wvMonth.addScrollingListener(new OnWheelScrollListener() { @Override public void onScrollingStarted(WheelView wheel) { // TODO Auto-generated method stub } @Override public void onScrollingFinished(WheelView wheel) { // TODO Auto-generated method stub String currentText = (String) mMonthAdapter.getItemText(wheel.getCurrentItem()); setTextviewSize(currentText, mMonthAdapter); } }); wvDay.addChangingListener(new OnWheelChangedListener() { @Override public void onChanged(WheelView wheel, int oldValue, int newValue) { // TODO Auto-generated method stub String currentText = (String) mDaydapter.getItemText(wheel.getCurrentItem()); setTextviewSize(currentText, mDaydapter); selectDay = currentText; } }); wvDay.addScrollingListener(new OnWheelScrollListener() { @Override public void onScrollingStarted(WheelView wheel) { // TODO Auto-generated method stub } @Override public void onScrollingFinished(WheelView wheel) { // TODO Auto-generated method stub String currentText = (String) mDaydapter.getItemText(wheel.getCurrentItem()); setTextviewSize(currentText, mDaydapter); } });
然后弹出的弹窗popuwindows里,设置时间
public String getYear() { Calendar c = Calendar.getInstance(); return c.get(Calendar.YEAR)+""; } public String getMonth() { Calendar c = Calendar.getInstance(); return c.get(Calendar.MONTH) + 1+""; } public String getDay() { Calendar c = Calendar.getInstance(); return c.get(Calendar.DATE)+""; } public void initData() { setDate(getYear(), getMonth(), getDay()); this.currentDay = 1+""; this.currentMonth = 1+""; } /** * 设置年月日 * * @param year * @param month * @param day */ public void setDate(String year, String month, String day) { selectYear = year + "年"; selectMonth = month + "月"; selectDay = day + "日"; issetdata = true; this.currentYear = year; this.currentMonth = month; this.currentDay = day; if (year == getYear()) { this.month = getMonth(); } else { this.month = 12+""; } calDays(year, month); } /** * 设置年份 * * @param year */ public int setYear(String year) { int yearIndex = 0; if (!year.equals(getYear())) { this.month = 12+""; } else { this.month = getMonth(); } for (int i = Integer.parseInt(getYear()); i > 1950; i--) { if (i == Integer.parseInt(year)) { return yearIndex; } yearIndex++; } return yearIndex; } /** * 设置月份 * * @param month * @param month * @return */ public int setMonth(String month) { int monthIndex = 0; calDays(currentYear, month); for (int i = 1; i < Integer.parseInt(this.month); i++) { if (Integer.parseInt(month) == i) { return monthIndex; } else { monthIndex++; } } return monthIndex; } /** * 计算每月多少天 * * @param month * @param year */ public void calDays(String year, String month) { boolean leayyear = false; if (Integer.parseInt(year) % 4 == 0 && Integer.parseInt(year) % 100 != 0) { leayyear = true; } else { leayyear = false; } for (int i = 1; i <= 12; i++) { switch (Integer.parseInt(month)) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: this.day = 31+""; break; case 2: if (leayyear) { this.day = 29+""; } else { this.day = 28+""; } break; case 4: case 6: case 9: case 11: this.day = 30+""; break; } } if (year.equals( getYear()) && month .equals( getMonth())) { this.day = getDay(); }然后设置点击事件
@Override public void onClick(View v) { if (v == btnSure) { if (onBirthListener != null) { onBirthListener.onClick(selectYear, selectMonth, selectDay); Log.d("cy",""+selectYear+""+selectMonth+""+selectDay); } } else if (v == btnSure) { } else { dismiss(); } dismiss(); }其实就是点击确定保存选择的日期,取消dismiss
底下确定键是黄色按钮那个就是换了个样式而已原理都是一样的
感谢阅读:
demo地址:https://github.com/PangHaHa12138/TimePackdemo