一,这一章来说是用来创建对话框的,要使用对话框就要使用AlertDialog,我们应该将AlertDialog封装在DialogFragment(Fragment)的实例中使用,这样子通过使用FragmentManager来管理对话可以更加灵活地显示对话框。因为如果直接使用对话框的话,旋转设备时Dialog会消失,但是封装在fragment中的就不会有这样的问题存在,这样子要使用对话框,我们应该按下面的步骤来创建
(1)我们应该先创建一个fragment
(2)然后在fragment中去创建和配置显示对话框的实例
(3)然后由一个activity来托管上面创建的fragment。
也就是 对应创建(1)DatePickerFragment类(2)创建AlertDialog(3)借助FragmentManager在屏幕上显示对话框,最后应该配置使用DatePicker,和实现在CrimeFragment和DatePickerFragment之间去传递数据
二。创建DatePickerFragment新类,并设置DialogFragment超类为支持库中的DialogFragment类,然后去实现onCreateDialog(Bundle be)方法,然后为了在屏幕上去显示DialogFragment,托管的FragmentManager会去调用它,如下面的代码:
public class DateDialogFragment extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState){
return new AlertDialog.Builder(getActivity())
.setTitle();
.setPositiveButton();.create();
}
}
三.要显示DialogFragment,和其他的fragment一样,DialogFragment实例也是由托管activity的FragmentManager来管理的,要将DialogFragment添加给FragmentManager管理并放置在屏幕上,可以调用fragment的以下方法,
public void show(FragmentManager manager,String tag);
public void show(FragmentTransation transation,String tag)
String参数是可以唯一识别FragmentManager队列中的DialogFragment,两个方法都可以使用,但后面那个需要我们自己负责创建和提交事务,前者的话会自动创建和提交事务,
四。我们在需要显示的碎片里面来添加一个tag,然后再onCreateView()方法中,去展示DatePickerFragment的界面
public class CrimeFragment extends Fragment {
private static final String DIALOG_DATE = "DialogDate";
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState){
mButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
FragmentManager manager = getFragmentManager();
DatePickerFragment dialog = new DatePickerFragment();
dialog.show(manager,DIALOG_DATE);
}
});
}
}
五.设置对话框中要显示的内容,应该使用AlertDialog的setView()方法,该方法配置对话框,实现在标题栏和按钮之间去显示传入的View对象,在项目工具窗口中,以DatePicker为根目录,创建名为dial_date.xml的布局文件,新布局里面只有一个View的对象,就是我们生成和传递给setView()方法的DatePicker视图,
然后在onCreateDialog()方法中去实例化DatePicker视图和添加给对话框,如下面的代码:
View v = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_date,null);
然后在AlertDialog.Builder()后面添加setView(v);
其实,我们也可以使用代码来添加对象,但是我们还是使用定义xml布局文件的方法好,因为使用布局文件的时候,想要调整布局文件会容易一些,还有就是但设备旋转时,用户选择的日期也会得到保留,这是因为设备配置改变时,具有ID属性的视图可以保存运行状态,我们使用布局的时候,编译的工具已经为DatePicker生成了唯一的ID。
六.fragment间的数据传递。要实现同一activity中两个fragment之间的数据传递,那么可以新建立一个newInstance(Date),然后将Date作为argument附加给fragment,为返回新日期给接受的fragment,并更新模型层,和对应的视图,那么就需要将日期打包好为extra并附加到Intent上面,然后调用Crime.onActivityResult()方法,并传入准备好的Intent,
下面时传送数据给DatePickerFragment,创建和设置fragment argument通常是在newInstance()方法中完成的,
public class DatePickerFragment extends DialogFragment {
private static final String ARG_DATE = "date";
private DatePicker mDatePicker;
public static DatePickerFragment newInstance(Date date) {
Bundle args = new Bundle();
args.putSerializable(ARG_DATE,date);
DatePickerFragment fragment = new DatePickerFragment();
fragment.setArgument(args);
return fragment;
}
}
然后在CrimeFragment中,用DatePickerFragment.newInstance(Date)方法来替换DatePickerFragment的构造方法。
换成DatePickerFragment dialog = DatePickerFragment.newInstance(mCrime.getDate());
七.对应DatePickerFragment,DatePicker对象的初始化需要整数形式的月,日,年,但date无法直接提供整数,那么对应着。我们就需要使用一个Calendar对象,然后用Date来配置它,再从Calendar对象中去获得所需要的东西
下面是在onCreateDialog()方法中,从argument中获取Date对象,然后用它和Calendar对象初始化DatePicker;
Date date = (Date)getArguments().getSerializable(ARG_DATE);
Calendar calendar = Calendar.getInstance();
calendar.setTime(Date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
mDatePicker = (DatePicker)v.findViewById(R.id.dialog_date_picker);
mDatePicker.init(year,month,day,null);
按照上面的做法我们就完成了从CrimeFragment向DatePickerFragment传递日期
八.这边是传递数据给CrimeFragment
如果是activity的数据回传,那么我们调用startAvtivityForResult()方法,ActivityManager负责跟踪管理activity父子关系,回传数据后,子activity被销毁,但ActivityManager知道接受数据的是哪一个activity
但对于fragment来说,我们需要通过设置他们的目标fragment来建立关系,运用setTargetFragment(Fragment fragment,int requestCode),第一个参数是目标fragment,第二个是请求代码,
目标fragment和请求代码由FragmentManager负责管理,我们可以调用fragment(设置目标fragment的fragment)的getTargetFragment()方法和getTargetRequestCode()来获取他们使用下面的代码
在CrimeFragment中使用下面的代码:
private static final int REQUEST = 0;
在呈现dialog前添加下面的代码:
dialog.setTargetFragment(CrimeFragment.this,REQUEST_DATE);
当建立好CrimeFragment与DatePickerFragment之间的关系后,就需要将数据回传给CrimeFragment了,回传日期将作为extra附加给Intent.
我们会让DatePickerFragment类调用CrimeFragment.onActivityResult(int,int,Intent)方法,这样我们应该在DatePickerFragment类中去新建一个sendResult()私有方法,创建intent并将日期数据作为extra附加到intent上,最后调用Crime.onActivityResult()方法,如下面的代码:
在DatePickerFragment中
public static final String EXTRA_DATE = "com.bignerdra.....";
private void sendResult(int resultCode,Date date){
if(getTargetFragment()==null){
return;
}
Intent intent = new Intent();
intent.putExtra(EXTRA_DATE,date);
getTargetFragment().onActivityResult(getTargetRequestCode(),resultCode,intent);
}
然后我们就可以在onClick()方法中去获得日期并调用sendResult()方法,
最后我们应该在CrimeFragment中去覆盖onActivityResult(),从extra中去获得日期数据,设置对应的Crime的记录日期,然后刷新日期按钮的显示,如下面的代码:
public void onActivityResult(int requestCode,int resultCode,Intent date){
if(resultCode !=Activity.RESULT_OK){
return;
}
if(requestCode == REQUEST_DATE){
Date date = (Date)date.getSerializableExtra(DatePickerFragment.EXTRA_DATE);
mCrime.setDate(Date);
mDateButton.setText(mCrime.getDate().toString());
}
}
而对于重复的代码。我们可以把他们放在一个私有的方法中去,右击 Refactor -> Extrat ->Method
九.对于需要更加灵活的DialogFeagment视图展示的话,如果是平板屏幕比较大的,那么就适合以对话框的方式来显示信息和接受用户输入,这种情况就应该设置目标的fragment并调用fragment的show方法,当对话框被取消之后,对话框fragment会调用目标fragment的onActivityResult()方法,无论启动子activity还是显示对话框,fragment的onActivityResult()方法总会被调用的,因此可以使用相同的代码来实现不同的信息呈现
如果要编写相同的代码用于全屏的fragment或是对话框fragment,可以选择覆盖DialogFragment.onCreateView(),而不是onCreateDialog()方法