Android

Java安卓学习总结(十六)

第十二章 对话框

有关AlertDialog

AlertDialog是Dialog的子类,可以在当前的界面上显示一个对话框,这个对话框是置顶于所有界面元素之上的,能够屏蔽掉其他控件的交互能力,因此AlertDialog一般是用于提示一些非常重要的内容或者警告信息。

AlertDialog.Builder

AlertDialog.Builder(getActivity()).setView(v).setTitle(R.string.date_picker_title).setPositiveButton(android.R.string.ok, null).create();

这个类用流式接口的方式创建AlertDialog实例,在public Dialog onCreateDialog(@Nullable Bundle savedInstanceState)中调用。等价于

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setView(v);
    builder.setTitle(R.string.date_picker_title);
    builder.setPositiveButton(android.R.string.ok, null);
    builder.create();  

还有一些其它可以用到的方法:

- setTitle:设置对话框的标题,比如“提示”、“警告”等; 
- setMessage:设置对话框要传达的具体信息; 
- setIcon: 设置对话框的图标; 
- setCancelable: 点击对话框以外的区域是否让对话框消失,默认为true; 
- setPositiveButton:设置正面按钮,表示“积极”、“确认”的意思,第一个参数为按钮上显示的文字,下同; 
- setNegativeButton:设置反面按钮,表示“消极”、“否认”、“取消”的意思; 
- setNeutralButton:设置中立按钮; 
- setOnShowListener:对话框显示时触发的事件; 
- setOnCancelListener:对话框消失时触发的事件。

DialogFragment.show()

创建出的AlertDialog实例需要通过DialogFragment来显示。有两种方法将DialogFragment添加给FragmentManager来管理:

public static show(FragmentManager manager,String tag)
public static show(FragmentTransaction Transaction ,String tag)

这里的tag适用于唯一标识FragmentManager队列中的DialogFragment,相当于建立一个键值对(不是)。区别在于第一种是自动帮你提交事务的。

有关DatePicker

DatePicker是一个可以选择日期的布局类型,可以设置初始的日期时间,也可以从这个布局上获得当前选择的日期。

//初始化
mDatePicker.init(year,month,day,null);
//获取
int year=mDatePicker.getYear();
int month=mDatePicker.getMonth();
int day=mDatePicker.getDayOfMonth();

还有其它的方法可以参照这里。

有关同一Activity下的Fragment之间的数据传递

发送数据

和之前没什么区别,就是利用Fragment的Arguments。例如我在DatePickerFragment中定义一个newInstance,在CrimeFragment中调用之并且附加信息。

返回数据

方式和父子Activity之间、Activity到Fragment之间返回数据一样使用startActivityForResult和onActivityResult方法。只不过这两个Fragment之间不存在父子关系,因此需要多做一步设置目标TargetFragment。

public void setTargetFragment(Fragment fragment,int requestCode)

第一个参数是目标Fragment,第二个参数是请求代码。这两个东西可以分别用getTargetFragment()和getTargetRequestCode()获取。

将数据传回时,需要调用的是目标Fragment的onActivityResult方法,我觉得这个是很显然的东西,不知道书上为什么要说这很难以置信。

重写目标Fragment的onActivityResult方法,使对应的RequestCode下处理返回结果信息,并在源Fragment中调用onActivityResult方法即可。

关于挑战练习 更多对话框

就是照着DatePicker的方式在写一个Fragment和布局文件,只不过用的是TimePicker而已。

有一些小细节需要处理:

TimePicker没有初始化方法,但是可以直接设置其hour和minute。

mTimePicker.setCurrentHour(hour);
mTimePicker.setCurrentMinute(mimute);

用GregorianCalendar()来实例化一个Date,必须要加上年月日,在此处年月日是之前传进来的Date,因此之前的Calender要final一下。

final Calendar calendar=Calendar.getInstance();
calendar.setTime(date);
int hour=calendar.get(Calendar.HOUR);
int mimute=calendar.get(Calendar.MINUTE);
...
...new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                int year=calendar.get(Calendar.YEAR);
                int month=calendar.get(Calendar.MONTH);
                int day=calendar.get(Calendar.DAY_OF_MONTH);
                int hour=mTimePicker.getCurrentHour();
                int minute=mTimePicker.getCurrentMinute();
                Date date=new GregorianCalendar(year,month,day,hour,minute).getTime();
                sendResult(Activity.RESULT_OK,date);
            }

TimePacker有一个监听器setOnTimeChangedListener,但是我们不需要,因为我们并不关心时间变化的过程;我们只需要关注点下按钮那一刻的时间即可。

GIF 2020 6 18 21 45 44

关于挑战练习 实现响应式DialogFragment

一开始用@Override没找到DialogFragment的onCreateView(),我以为这个方法被隐藏了,使得我又去重新写了一个Fragment。但是刚刚又发现可以找到了,还要只需要重新移动过来就好了,改动不大。

DatePickerActivity

继承SingleFragmentActivity方法,并且写一个newInstance方法方便父类的Fragment(CrimeFragment)创建其实例。

CrimeFragment

在原来创建DialogFragment的地方改写成startActivityForResult方法:

mDataButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
/*
FragmentManager manager =getFragmentManager();
DatePickerFragment dialog=DatePickerFragment.newInstance(mCrime.getDate());
dialog.setTargetFragment(CrimeFragment.this,REQUEST_DATE);
dialog.show(manager,DIALOG_DATE);

*/
Intent intent=DatePickerActivity.newIntent(getActivity(),mCrime.getDate());
startActivityForResult(intent,REQUEST_DATE);

}
});

DatePickerFragment

在DatePickerFragment中只需要重写onCreateView方法,下面两个方法是可以直接用的,不需要改。

public static DatePickerFragment newInstance(Date date){}
...
private void sendResult(int resultCode,Date date){}

而在onCreateView方法中,大部分代码都一样,只是两者的按钮监听器内容写法有差别,需要调用托管它的Activity方法的setResult来完成将消息传递回父Activity的Fragment(CrimeFragment)。

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.dialog_date_new,container,false);

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);

mButton=(Button)v.findViewById(R.id.fragment_date_picker_ok);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int year=mDatePicker.getYear();
int month=mDatePicker.getMonth();
int day=mDatePicker.getDayOfMonth();
Date date=new GregorianCalendar(year,month,day).getTime();
Intent intent=new Intent();
intent.putExtra(EXTRA_DATE,date);
//Toast.makeText(getActivity(),getActivity().getLocalClassName().toString(),Toast.LENGTH_SHORT).show();
getActivity().setResult(Activity.RESULT_OK,intent);
getActivity().finish();
}
});

mDatePicker=(DatePicker) v.findViewById(R.id.dialog_date_picker);
mDatePicker.init(year,month,day,null);

return v;
}

有一个地方要注意的是,点了ok按钮之后最好是需要立刻结束这个Fragment的,所以直接调用托管Activity的finish()方法即可。

GIF 2020 6 18 21 46 40

发表评论