本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导。在京东即可购买:https://item.jd.com/12385680.html
在较高版本的Android SDK中, 已经修改默认的日期选择控件, 由滚轮样式变为日历样式. 对于出生日期的选择, 为了美观, 也为了便捷, 滚轮控件更有优势, 因此需要编写自定义的时间滚轮控件. 随手记也使用这类控件设置时间, 非常喜欢. 本着开源的原则, 已共享这些源码.
本文源码的GitHub下载地址
Dialog
初始化底部弹窗, 自定义功能与样式.
@NonNull @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(getActivity(), R.style.Dialog_NoTitle);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(true); // 后退键取消
dialog.setCanceledOnTouchOutside(true); // 点击外面被取消
dialog.setContentView(initView()); // 设置View
return dialog;
}
创建时间滚轮, 绑定当前布局与参数.
mTimeWheel = new TimeWheel(view, mScrollerConfig); // 设置滚动参数
根据时间滚轮的位置, 返回当前选择的时间, 通过接口回调.
private void onSureClicked() {
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.YEAR, mTimeWheel.getCurrentYear());
calendar.set(Calendar.MONTH, mTimeWheel.getCurrentMonth() - 1);
calendar.set(Calendar.DAY_OF_MONTH, mTimeWheel.getCurrentDay());
calendar.set(Calendar.HOUR_OF_DAY, mTimeWheel.getCurrentHour());
calendar.set(Calendar.MINUTE, mTimeWheel.getCurrentMinute());
mCurrentMilliseconds = calendar.getTimeInMillis();
if (mScrollerConfig.mCallback != null) {
mScrollerConfig.mCallback.onDateSet(this, mCurrentMilliseconds);
}
dismiss();
}
布局使用渐变蒙版作为背景, 顶部和底部纯白, 至中间透明, 使用layer-list的梯度gradient属性模拟效果.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="100dp"
android:gravity="top">
<shape android:shape="rectangle">
<gradient
android:angle="90"
android:endColor="@android:color/white"
android:startColor="@android:color/transparent"/>
</shape>
</item>
<item
android:gravity="bottom"
android:top="100dp">
<shape android:shape="rectangle">
<gradient
android:angle="90"
android:endColor="@android:color/transparent"
android:startColor="@android:color/white"/>
</shape>
</item>
</layer-list>
时间滚轮
页面含有多个滚轮, 高级时间控制低级时间, 年时间控制年月日小时, 月时间控制月日小时, 等等. 比如修改月, 日的范围就会不同(28~31), 需要联合滚动.
mYearView.addChangingListener(mYearListener);
mYearView.addChangingListener(mMonthListener);
mYearView.addChangingListener(mDayListener);
mYearView.addChangingListener(mHourListener);
mMonthView.addChangingListener(mMonthListener);
mMonthView.addChangingListener(mDayListener);
mMonthView.addChangingListener(mHourListener);
mDayView.addChangingListener(mDayListener);
mDayView.addChangingListener(mHourListener);
mHourView.addChangingListener(mHourListener);
初始化月份, 根据年份选择当前项, 并设置滚轮是否循环.
private void initMonthView() {
updateMonths();
int curYear = getCurrentYear();
int minMonth = mRepository.getMinMonth(curYear);
mMonthView.setCurrentItem(mRepository.getDefaultCalendar().month - minMonth);
mMonthView.setCyclic(mScrollerConfig.cyclic);
}
更新月份, 不可见返回, 获取最大月与最小月, 并初始化适配器, 为滚轮设置适配器, 如果当前月小于最小月, 则自动滚动.
private void updateMonths() {
if (mMonthView.getVisibility() == View.GONE)
return;
int curYear = getCurrentYear();
int minMonth = mRepository.getMinMonth(curYear);
int maxMonth = mRepository.getMaxMonth(curYear);
mMonthAdapter = new NumericWheelAdapter(mContext, minMonth, maxMonth,
DateConstants.FORMAT, mScrollerConfig.mMonth);
mMonthAdapter.setConfig(mScrollerConfig);
mMonthView.setViewAdapter(mMonthAdapter);
if (mRepository.isMinYear(curYear)) {
mMonthView.setCurrentItem(0, false);
}
}
TimeRepository根据默认参数与设置参数, 获取最大与最小值.
其他时间设置类似.
使用
通过装饰者模式设置Dialog的参数, 如类型, 标题, 最小最大当前时间, 回调. 注意在Dialog使用时, 防止重复添加, 需要判断isAdded.
public void showDate(View view) {
// 出生日期
DateScrollerDialog dialog = new DateScrollerDialog.Builder()
.setType(Type.YEAR_MONTH_DAY)
.setTitleStringId("请选择出生日期")
.setMinMilliseconds(System.currentTimeMillis() - HUNDRED_YEARS)
.setMaxMilliseconds(System.currentTimeMillis())
.setCurMilliseconds(mLastTime)
.setCallback(mOnDateSetListener)
.build();
if (dialog != null) {
if (!dialog.isAdded()) {
dialog.show(getSupportFragmentManager(), "year_month_day");
}
}
}
设置时间的回调, 点击确定即会触发, 保持上次时间, 在重复使用的初始化时使用.
// 数据的回调
private OnDateSetListener mOnDateSetListener = new OnDateSetListener() {
@Override public void onDateSet(DateScrollerDialog timePickerView, long milliseconds) {
mLastTime = milliseconds;
String text = getDateToString(milliseconds);
mTvTime.setText(text);
}
};
效果
其中部分源码参考其他滚轮控件.
时间滚轮控件需要处理的联动情况较多, 分离表示层与数据层使得业务逻辑更加清晰.
OK, that's all! Enjoy it!