安卓開發過程中難免會碰到需要選擇日期時間的情況,由於大部分android初級教程都沒教怎麼選擇時間,初學者碰到這種難免會有些不知所措,難道要讓用戶自己輸入日期時間?先不說用戶體驗不好,處理用戶輸入各式各樣的日期格式也要花好大一番功夫。 所以當然不可能讓用戶自己輸入日期時間,筆者收集整理了一些資料,總 ...
安卓開發過程中難免會碰到需要選擇日期時間的情況,由於大部分android初級教程都沒教怎麼選擇時間,初學者碰到這種難免會有些不知所措,難道要讓用戶自己輸入日期時間?先不說用戶體驗不好,處理用戶輸入各式各樣的日期格式也要花好大一番功夫。
所以當然不可能讓用戶自己輸入日期時間,筆者收集整理了一些資料,總結了一下如何實現android選擇時間的功能,方便後來者參考
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
android 6.0 中的運行效果
TimePickerDialog和DatePickerDialog介紹
系統封裝好了兩個類可以供我們直接調用,TimepickerDialog用於選擇時間,DatePickerDialog用於選擇日期。
TimePikckerDialog的構造方法
public TimePickerDialog(Context context, OnTimeSetListener listener, int hourOfDay, int minute, boolean is24HourView)
- 第一個參數接受一個context信息
- 第二個參數為當選擇時間完成後執行的回調介面
- 第三個參數和第四個參數為初始化的時間
- 第四個參數選擇true代表24小時制,false代表12小時制
DatePickerDialog構造方法
public DatePickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth)
- 第一個參數接受context信息
- 第二個參數為日期選擇完成後的回掉介面
- 最後三個參數分別為初始化的年月日
可以看出兩者的構造方法基本相差不多,由於兩者都是繼承自AlertDialog,所以得到兩者對象後只要調用它們的show()方法即可將選擇框彈出。
具體實現
有兩種實現方式,一種是直接在Activity中使用,還有一種是通過FragmentDialog使用。
直接在Activity中使用比較簡單,不過代碼會比較亂,通過FragmentDialog管理的使用方式會比較優雅,而且便於管理。
直接在Activity中使用
佈局文件,裡面就一個TextView用於顯示所選時間
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.testdemo.TestActivity">
<TextView
android:layout_centerInParent="true"
android:textSize="20sp"
android:id="@+id/time_text"
android:text="點此選擇時間"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
Activity文件:
public class TestActivity extends AppCompatActivity {
private TextView timeText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
timeText = (TextView) findViewById(R.id.time_text);
//為TextView設置點擊事件
timeText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//將timeText傳入用於顯示所選擇的時間
showDialogPick((TextView) v);
}
});
}
//將兩個選擇時間的dialog放在該函數中
private void showDialogPick(final TextView timeText) {
final StringBuffer time = new StringBuffer();
//獲取Calendar對象,用於獲取當前時間
final Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
//實例化TimePickerDialog對象
final TimePickerDialog timePickerDialog = new TimePickerDialog(TestActivity.this, new TimePickerDialog.OnTimeSetListener() {
//選擇完時間後會調用該回調函數
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
time.append(" " + hourOfDay + ":" + minute);
//設置TextView顯示最終選擇的時間
timeText.setText(time);
}
}, hour, minute, true);
//實例化DatePickerDialog對象
DatePickerDialog datePickerDialog = new DatePickerDialog(TestActivity.this, new DatePickerDialog.OnDateSetListener() {
//選擇完日期後會調用該回調函數
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
//因為monthOfYear會比實際月份少一月所以這邊要加1
time.append(year + "-" + (monthOfYear+1) + "-" + dayOfMonth);
//選擇完日期後彈出選擇時間對話框
timePickerDialog.show();
}
}, year, month, day);
//彈出選擇日期對話框
datePickerDialog.show();
}
}
到此,點擊運行就可以看效果了:)
通過FragmentDialog使用
為什麼要用DialogFragment
- 用DialogFragment管理對話框是官方推介的使用方式。
- 使用DialogFragment管理對話框也方便代碼的重用。
- 如果你想瞭解更多可以看看詳細解讀DialogFragment,裡面講的很詳細。
通過FragmentDialog實現步驟
- DatePickerFragment類:
public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener{
private String date;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//得到Calendar類實例,用於獲取當前時間
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//返回DatePickerDialog對象
//因為實現了OnDateSetListener介面,所以第二個參數直接傳入this
return new DatePickerDialog(getActivity(), this, year, month, day);
}
//實現OnDateSetListener介面的onDateSet()方法
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
//這樣子寫就將選擇時間的fragment和選擇日期的fragment完全綁定在一起
//使用的時候只需直接調用DatePickerFragment的show()方法
//即可選擇完日期後選擇時間
TimePickerFragment timePicker = new TimePickerFragment();
timePicker.show(getFragmentManager(), "time_picker");
//將用戶選擇的日期傳到TimePickerFragment
date = year + "年" + (monthOfYear+1) + "月" + dayOfMonth + "日";
timePicker.setTime(date);
}
}
- TimePickerFragment類:
//實現OnTimeSetListener介面
public class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener{
private String time = "";
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//新建日曆類用於獲取當前時間
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
//返回TimePickerDialog對象
//因為實現了OnTimeSetListener介面,所以第二個參數直接傳入this
return new TimePickerDialog(getActivity(), this, hour, minute, true);
}
//實現OnTimeSetListener的onTimeSet方法
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
//判斷activity是否是DataCallBack的一個實例
if(getActivity() instanceof DataCallBack){
//將activity強轉為DataCallBack
DataCallBack dataCallBack = (DataCallBack) getActivity();
time = time + hourOfDay + "點" + minute + "分";
//調用activity的getData方法將數據傳回activity顯示
dataCallBack.getData(time);
}
}
public void setTime(String date){
time += date;
}
}
- Activity的佈局文件,只有一個TextView用於顯示時間
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.testdemo.TestActivityActivity">
<TextView
android:id="@+id/time_text"
android:layout_centerInParent="true"
android:text="點此選擇時間"
android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
- Activity文件:
//實現DataCallBack介面,實現與Fragment的通信
public class TestActivityActivity extends AppCompatActivity implements DataCallBack{
TextView timeText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test2);
timeText = (TextView) findViewById(R.id.time_text);
//為timeText設置點擊事件
timeText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//實例化對象
DatePickerFragment datePickerFragment = new DatePickerFragment();
//調用show方法彈出對話框
// 第一個參數為FragmentManager對象
// 第二個為調用該方法的fragment的標簽
datePickerFragment.show(getFragmentManager(), "date_picker");
}
});
}
//實現DataCallBack的getData方法
@Override
public void getData(String data) {
//data即為fragment調用該函數傳回的日期時間
timeText.setText(data);
}
}
由於TimePickerFragment對話框是在DatePickerFragment類裡面啟動的,所以這樣寫只能日期和時間都選擇,如果要單獨選擇日期或者時間,只需要重寫onTimeSet()或者onDateSet()方法即可
相容性問題
不同的android版本顯示的效果不同,在android6.0效果很好,不過在一些低版本android(如4.0,筆者沒有每個版本都測試)會出現調用兩次回掉函數的情況,導致選擇兩次時間。解決的辦法有很多,只要保證回調函數裡面的邏輯只執行一次就可以。這裡提供一種比較通用的方法。
重寫TimePickerDialog和DatePickerDialog的onStop()方法
- 直接在Activity中使用的重寫方法
final TimePickerDialog timePickerDialog = new TimePickerDialog(TestActivity.this, new TimePickerDialog.OnTimeSetListener() {
//選擇完時間後會調用該回調函數
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
time.append(" " + hourOfDay + ":" + minute);
//設置TextView顯示最終選擇的時間
timeText.setText(time);
}
}, hour, minute, true){
// 重寫onStop()
@Override
protected void onStop() {
}
};
//實例化DatePickerDialog對象
DatePickerDialog datePickerDialog = new DatePickerDialog(TestActivity.this, new DatePickerDialog.OnDateSetListener() {
//選擇完日期後會調用該回調函數
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
//因為monthOfYear會比實際月份少一月所以這邊要加1
time.append(year + "-" + (monthOfYear+1) + "-" + dayOfMonth);
//選擇完日期後彈出選擇時間對話框
timePickerDialog.show();
}
}, year, month, day){
//重寫onstop
@Override
protected void onStop() {
}
};
上面的寫法看起來會比較亂,也可以另外新建一個類繼承TimePickerDialog或者DatePickerDialog然後重寫onStop()方法
- 通過FragmentDialog使用的重寫方式
只需在onCreateDialog()方法裡面重寫即可,下麵的代碼會比較清晰
return new DatePickerDialog(getActivity(), this, year, month, day){
// 重寫onStop
@Override
protected void onStop() {
}
};
return new TimePickerDialog(getActivity(), this, hour, minute, true){
//重寫onStop
@Override
protected void onStop() {
}
};
筆者水平有限,但是保證以上代碼都是親手實現過一遍的。如果有什麼不足之處歡迎大家指出^_^。
參考
解決TimePickerDialog中onTimeSet執行兩次的問題