You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gitProject/other/07_210340164温雍敬_代码标注/ui/DateTimePicker.java

391 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui;
import java.text.DateFormatSymbols;
import java.util.Calendar;
import net.micode.notes.R;
import android.content.Context;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.NumberPicker;
public class DateTimePicker extends FrameLayout {
private static final boolean DEFAULT_ENABLE_STATE = true;
private static final int HOURS_IN_HALF_DAY = 12;// 半天内的小时数
private static final int HOURS_IN_ALL_DAY = 24;// 全天的小时数
private static final int DAYS_IN_ALL_WEEK = 7;// 一周的天数
private static final int DATE_SPINNER_MIN_VAL = 0;// 日期选择器的最小值
private static final int DATE_SPINNER_MAX_VAL = DAYS_IN_ALL_WEEK - 1;// 日期选择器的最大值
private static final int HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW = 0;// 在24小时显示模式下小时选择器的最小值
private static final int HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW = 23;// 在24小时显示模式下小时选择器的最大值
private static final int HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW = 1;// 在12小时显示模式下小时选择器的最小值
private static final int HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW = 12;// 在12小时显示模式下小时选择器的最大值
private static final int MINUT_SPINNER_MIN_VAL = 0;// 分钟选择器的最小值
private static final int MINUT_SPINNER_MAX_VAL = 59;// 分钟选择器的最大值
private static final int AMPM_SPINNER_MIN_VAL = 0;// 上下午选择器的最小值
private static final int AMPM_SPINNER_MAX_VAL = 1;// 上下午选择器的最大值
private final NumberPicker mDateSpinner;// 日期选择器
private final NumberPicker mHourSpinner;// 小时选择器
private final NumberPicker mMinuteSpinner;// 分钟选择器
private final NumberPicker mAmPmSpinner;// 上下午选择器
private Calendar mDate;// 当前选择的日期
private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK];// 日期选择器的展示值,周一到周日
private boolean mIsAm;// 是否是上午默认为true
private boolean mIs24HourView;// 是否使用24小时显示模式
private boolean mIsEnabled = DEFAULT_ENABLE_STATE;// 控件是否可用默认为true
private boolean mInitialising;// 是否还在初始化过程中
private OnDateTimeChangedListener mOnDateTimeChangedListener;// 选择时间后的回调接口
// 当日期改变时的监听器
private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
// 更新当前已选日期
mDate.add(Calendar.DAY_OF_YEAR, newVal - oldVal);
// 更新日期选择器
updateDateControl();
// 回调选择时间后的接口方法
onDateTimeChanged();
}
};
// 当小时改变时的监听器
private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean isDateChanged = false;// 是否需要改变日期的标识
Calendar cal = Calendar.getInstance();
if (!mIs24HourView) {// 使用12小时制
if (!mIsAm && oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) {
// 如果从上午11点到下午12点则需要向后加一整天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
} else if (mIsAm && oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
// 如果从下午12点到上午11点则需要向前减一整天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}
if (oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY ||
oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1) {
// 切换上下午
mIsAm = !mIsAm;
updateAmPmControl();
}
} else {// 使用24小时制
if (oldVal == HOURS_IN_ALL_DAY - 1 && newVal == 0) {
// 如果从23点到0点则需要向后加一整天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, 1);
isDateChanged = true;
} else if (oldVal == 0 && newVal == HOURS_IN_ALL_DAY - 1) {
// 如果从0点到23点则需要向前减一整天
cal.setTimeInMillis(mDate.getTimeInMillis());
cal.add(Calendar.DAY_OF_YEAR, -1);
isDateChanged = true;
}
}
int newHour = mHourSpinner.getValue() % HOURS_IN_HALF_DAY + (mIsAm ? 0 : HOURS_IN_HALF_DAY);
mDate.set(Calendar.HOUR_OF_DAY, newHour);
onDateTimeChanged();
if (isDateChanged) {
setCurrentYear(cal.get(Calendar.YEAR));
setCurrentMonth(cal.get(Calendar.MONTH));
setCurrentDay(cal.get(Calendar.DAY_OF_MONTH));
}
}
};
// 当分钟改变时的监听器
private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
int minValue = mMinuteSpinner.getMinValue();
int maxValue = mMinuteSpinner.getMaxValue();
int offset = 0;
if (oldVal == maxValue && newVal == minValue) {
offset += 1;// 时间增加一小时
} else if (oldVal == minValue && newVal == maxValue) {
offset -= 1;// 时间减少一小时
}
if (offset != 0) {
mDate.add(Calendar.HOUR_OF_DAY, offset);// 根据偏移量调整时间
mHourSpinner.setValue(getCurrentHour());// 更新当前的小时数
updateDateControl();// 更新日期选择器
int newHour = getCurrentHourOfDay();
if (newHour >= HOURS_IN_HALF_DAY) {// 更新上下午选择器
mIsAm = false;
updateAmPmControl();
} else {
mIsAm = true;
updateAmPmControl();
}
}
mDate.set(Calendar.MINUTE, newVal);// 更新分钟数
onDateTimeChanged();// 回调接口方法
}
};
// 当上下午改变时的监听器
private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mIsAm = !mIsAm;// 切换上下午
if (mIsAm) {
mDate.add(Calendar.HOUR_OF_DAY, -HOURS_IN_HALF_DAY);
} else {
mDate.add(Calendar.HOUR_OF_DAY, HOURS_IN_HALF_DAY);
}
updateAmPmControl();// 更新上下午选择器
onDateTimeChanged();// 回调接口方法
}
};
// 选择时间后的回调接口
public interface OnDateTimeChangedListener {
void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute);
}
public DateTimePicker(Context context) {
this(context, System.currentTimeMillis());
}
public DateTimePicker(Context context, long date) {
this(context, date, DateFormat.is24HourFormat(context));
}
public DateTimePicker(Context context, long date, boolean is24HourView) {
super(context);
mDate = Calendar.getInstance();// 初始化当前日期为系统当前日期
mInitialising = true;// 开始初始化
// 加载布局文件
inflate(context, R.layout.datetime_picker, this);
// 初始化日期选择器
mDateSpinner = (NumberPicker) findViewById(R.id.date);
mDateSpinner.setMinValue(DATE_SPINNER_MIN_VAL);
mDateSpinner.setMaxValue(DATE_SPINNER_MAX_VAL);
mDateSpinner.setOnValueChangedListener(mOnDateChangedListener);
// 初始化小时选择器
mHourSpinner = (NumberPicker) findViewById(R.id.hour);
mHourSpinner.setOnValueChangedListener(mOnHourChangedListener);
// 初始化分钟选择器
mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
mMinuteSpinner.setMinValue(MINUT_SPINNER_MIN_VAL);
mMinuteSpinner.setMaxValue(MINUT_SPINNER_MAX_VAL);
mMinuteSpinner.setOnLongPressUpdateInterval(100);// 设置快速滑动时的更新间隔
mMinuteSpinner.setOnValueChangedListener(mOnMinuteChangedListener);
// 初始化上下午选择器
String[] stringsForAmPm = new DateFormatSymbols().getAmPmStrings(); // 获取“上午”和“下午”字符串数组
AmPmSpinner = (NumberPicker) findViewById(R.id.amPm); // 实例化一个NumberPicker并通过ID获取布局中对应的视图
mAmPmSpinner.setMinValue(AMPM_SPINNER_MIN_VAL); // 设置NumberPicker的最小值
mAmPmSpinner.setMaxValue(AMPM_SPINNER_MAX_VAL); // 设置NumberPicker的最大值
mAmPmSpinner.setDisplayedValues(stringsForAmPm); // 设置NumberPicker的展示值为“上午”和“下午”
mAmPmSpinner.setOnValueChangedListener(mOnAmPmChangedListener); // 设置当用户更改NumberPicker的值时应执行的回调侦听器
// update controls to initial state更新控件的初始状态
updateDateControl(); // 更新日期控件的状态
updateHourControl(); // 更新小时控件的状态
updateAmPmControl(); // 更新上午下午控件的状态
set24HourView(is24HourView); // 根据is24HourView变量设置控件为“24小时制”或“AM/PM模式”
// set to current time将控件设置为当前时间
setCurrentDate(date); // 根据提供的时间设置当前时间
setEnabled(isEnabled()); // 根据isEnabled()方法返回的值设置控件是否启用
// set the content descriptions设置控件的内容描述
mInitialising = false; // 初始化完毕将mInitialising变量设置为false
// 获取当前时间的毫秒数
public long getCurrentDateInTimeMillis() {
return mDate.getTimeInMillis();
}
// 根据提供的时间设置当前时间
public void setCurrentDate(long date) {
Calendar cal = Calendar.getInstance(); // 获取Calendar实例
cal.setTimeInMillis(date); // 设置Calendar的时间为提供的时间
setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); // 根据Calendar的时间设置当前时间
}
// 根据提供的年月日时分设置当前时间
public void setCurrentDate(int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
setCurrentYear(year); // 设置当前年份
setCurrentMonth(month); // 设置当前月份
setCurrentDay(dayOfMonth); // 设置当前日
setCurrentHour(hourOfDay); // 设置当前小时
setCurrentMinute(minute); // 设置当前分钟
}
// 获取当前年份
public int getCurrentYear() {
return mDate.get(Calendar.YEAR);
}
// 设置当前年份
public void setCurrentYear(int year) {
if (!mInitialising && year == getCurrentYear()) {
return;
}
mDate.set(Calendar.YEAR, year);
updateDateControl(); // 更新日期控件
onDateTimeChanged(); // 调用回调方法告知“日期与时间”已更改
}
// 获取当前月份
public int getCurrentMonth() {
return mDate.get(Calendar.MONTH);
}
// 设置当前月份
public void setCurrentMonth(int month) {
if (!mInitialising && month == getCurrentMonth()) {
return;
}
mDate.set(Calendar.MONTH, month);
updateDateControl(); // 更新日期控件
onDateTimeChanged(); // 调用回调方法告知“日期与时间”已更改
}
// 获取当前日
public int getCurrentDay() {
return mDate.get(Calendar.DAY_OF_MONTH);
}
// 设置当前日
public void setCurrentDay(int dayOfMonth) {
if (!mInitialising && dayOfMonth == getCurrentDay()) {
return;
}
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
updateDateControl(); // 更新日期控件
onDateTimeChanged(); // 调用回调方法告知“日期与时间”已更改
}
// 获取当前小时24小时制
public int getCurrentHourOfDay() {
return mDate.get(Calendar.HOUR_OF_DAY);
}
// 获取当前小时12小时制
private int getCurrentHour() {
if (mIs24HourView){
return getCurrentHourOfDay();
} else {
int hour = getCurrentHourOfDay();
if (hour > HOURS_IN_HALF_DAY) {
return hour - HOURS_IN_HALF_DAY;
} else {
return hour == 0 ? HOURS_IN_HALF_DAY : hour;
}
}
}
// 设置当前小时
public void setCurrentHour(int hourOfDay) {
if (!mInitialising && hourOfDay == getCurrentHourOfDay()) {
return;
}
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
if (!mIs24HourView) {
if (hourOfDay >= HOURS_IN_HALF_DAY) {
mIsAm = false;
if (hourOfDay > HOURS_IN_HALF_DAY) {
hourOfDay -= HOURS_IN_HALF_DAY;
}
} else {
mIsAm = true;
if (hourOfDay == 0) {
hourOfDay = HOURS_IN_HALF_DAY;
}
}
updateAmPmControl(); // 更新上午下午控件
}
mHourSpinner.setValue(hourOfDay); // 更新小时控件
onDateTimeChanged(); // 调用回调方法告知“日期与时间”已更改
}
// 获取当前分钟
public int getCurrentMinute() {
return mDate.get(Calendar.MINUTE);
}
// 设置当前分钟
public void setCurrentMinute(int minute) {
if (!mInitialising && minute == getCurrentMinute()) {
return;
}
mMinuteSpinner.setValue(minute); // 更新分钟控件
mDate.set(Calendar.MINUTE, minute); // 更新Calendar的分钟字段
onDateTimeChanged(); // 调用回调方法告知“日期与时间”已更改
}
// 判断是否为24小时制
public boolean is24HourView () {
return mIs24HourView;
}
// 设置是否为24小时制
public void set24HourView(boolean is24HourView) {
if (mIs24HourView == is24HourView) {
return;
}
mIs24HourView = is24HourView;
mAmPmSpinner.setVisibility(is24HourView ? View.GONE : View.VISIBLE); // 根据是否为24小时制设置上午下午控件的可见性
int hour = getCurrentHourOfDay();
updateHourControl(); // 更新小时控件
setCurrentHour(hour); // 更新当前时间的小时字段
updateAmPmControl(); // 更新上午下午控件
}
// 设置回调方法,当“设置”按钮被按下时调用
public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback) {
mOnDateTimeChangedListener = callback;
}
// 回调方法,告知“日期与时间”已更改
private void onDateTimeChanged() {
if (mOnDateTimeChangedListener != null) {
mOnDateTimeChangedListener.onDateTimeChanged(this, getCurrentYear(),
getCurrentMonth(), getCurrentDay(), getCurrentHourOfDay(), getCurrentMinute());
}
}