创建DatePickerFragment
/**
* 使用DialogFragment(AlterDialog视图封装在DialogFragment中)而不使用AlertDialog,
* 这是Android开发原则推荐。 使用FragmentManager管理对话框,可使用更多配置选项来显示对话框。
* 另外,如果设备发生旋转,独立配置使用的AlterDialog会在旋转后消失
* ,而配置封装在DialogFragment中的AlertDialog则不会有此问题。
*/
public class DatePickerFragment extends DialogFragment {
public static final String EXTRA_DATE = "com.huangfei.criminalintent.date";
private Date mDate;
public static DatePickerFragment newInstance(Date date) {
Bundle bundle = new Bundle();
bundle.putSerializable(EXTRA_DATE, date);
DatePickerFragment fragment = new DatePickerFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mDate = (Date) getArguments().getSerializable(EXTRA_DATE);
/**
* DatePickerFragment需要使用Date中的信息来初始化DatePicker对象。然而,
* DatePicker对象的初始化需要整数形式的月、日、年。
* Date就是个时间戳,它无法直接提供整数形式的月、日、年。需先创建一个Calendar对象
* ,然后用Date对象对其进行配置,即可从Calendar对 象中取回所需信息。
*/
Calendar calendar = Calendar.getInstance();
calendar.setTime(mDate);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
View view = getActivity().getLayoutInflater().inflate(
R.layout.dialog_date, null);
DatePicker datePicker = (DatePicker) view
.findViewById(R.id.dialog_date_datePicker);
datePicker.init(year, month, day, new OnDateChangedListener() {
@Override
public void onDateChanged(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
mDate = new GregorianCalendar(year, monthOfYear, dayOfMonth)
.getTime();
/**
* 为防止设备旋转时发生Date数据的丢失,在onDateChanged(...)方法的尾部,
* 我们将Date对象回写保存到了fragment argument中。
*/
getArguments().putSerializable(EXTRA_DATE, mDate);
}
});
/**
* Android有3种可用于对话框的按钮:positive按钮、negative按钮、neutral按钮
*/
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.date_picker_title)// 设置对话框标题
.setView(view)// 设置对话框布局
.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
sendResult(Activity.RESULT_OK);
}
})// 设置对话框按钮
.create();
}
}
设置目标Fragment
mDateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager fm = getActivity().getSupportFragmentManager();
DatePickerFragment dialog = DatePickerFragment.newInstance(mCrime.getDate());
/**
* 同一Activity中,为了使CrimeFragment能够接受到DatePickerFragment返回的数据,可将CrimeFragment设置为
* DatePickerFragment的目标fragment,可调用方法:
* Fragment.setTargetFragment(Fragment, requestCode);
*
* 目标fragment以及请求码由FragmentManager负责跟踪记录,我们可调用fragment(设置目标fragment的fragment)的
* getTargetFragment()与getTargetRequestCode()方法获取它们。
*/
dialog.setTargetFragment(CrimeFragment.this, REQUEST_DATE);
/**
* 要将DialogFragment添加给FragmentManager管理并放置到屏幕上,可调用DialogFragment实例的以下方法:
* show(FragmentManager manager, String tag)
* show(FragmentTransaction transaction, String tag)
*
* string参数可唯一识别存放在FragmentManager队列中的DialogFragment。
*/
dialog.show(fm, DIALOG_DATE);
}
});
传递数据给目标fragment
/**
* 处理同一activity托管的两个fragment间的数据返回时,可借用Fragment.onActivityResult(...)方法。
* 因此,直接调用目标fragment的Fragment.onActivityResult(...)方法,即可实现数据的回传。
*
*/
private void sendResult(int resultCode) {
if (getTargetFragment() == null)
return;
Intent intent = new Intent();
intent.putExtra(EXTRA_DATE, mDate);
getTargetFragment().onActivityResult(getTargetRequestCode(),
resultCode, intent);
}
更为灵活的DialogFragment视图展现
手机的屏幕非常有限。因此,通常需要使用一个activity托管全屏的fragment界面,以显示用户输入要求。该子activity会由父activity的fragment以调用startActivityForResult(…)方法启动。子activity销毁后,父activity会收到onActivityResult(…)方法的调用请求,并将之转发给启动子activity的fragment。
平板设备屏幕比较大。因此,以弹出对话框的方式显示信息和接受用户输入通常会更好。这种情况下,应该设置目标fragment并调用对话框fragment的show(…)方法。对话框被取消后,对话框fragment会调用目标fragment的onActivityResult(…)方法。