安卓开发过程中难免会碰到需要选择日期时间的情况,由于大部分android初级教程都没教怎么选择时间,初学者碰到这种难免会有些不知所措,难道要让用户自己输入日期时间?先不说用户体验不好,处理用户输入各式各样的日期格式也要花好大一番功夫。
所以当然不可能让用户自己输入日期时间,笔者收集整理了一些资料,总结了一下如何实现android选择时间的功能,方便后来者参考
android 6.0 中的运行效果
系统封装好了两个类可以供我们直接调用,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管理的使用方式会比较优雅,而且便于管理。
布局文件,里面就一个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(); } }到此,点击运行就可以看效果了:)
为什么要用DialogFragment 1. 用DialogFragment管理对话框是官方推介的使用方式。 2. 使用DialogFragment管理对话框也方便代码的重用。 3. 如果你想了解更多可以看看详细解读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() { } };笔者水平有限,但是保证以上代码都是亲手实现过一遍的。如果有什么不足之处欢迎大家指出^_^。
android学习笔记(十二)日期、时间组件
详细解读DialogFragment
解决TimePickerDialog中onTimeSet执行两次的问题