第十二章 对话框Dialog
Dialog(对话框)
- 步骤:
- 引入相应的依赖项
- 创建继承
DialogFragment
的fragment类- 重写
onCreateDialog
,并可实例化有关布局。- 借助托管activity的
FragmentManager
会自动调用onCrea teDialog在屏幕上显示对话框。详情见后面的show
方法。使用AlertDialog
和AlertDialog.Builder(getActivity())
可以实现更多个性化需求。
- 将Dialog封装在对应的Fragment中,可以更加灵活的显示对话框且旋转设备后不会消失。具有ID属性的视图可以保存运行状态。
return new AlertDialog.Builder(getActivity())
.setView(v) //在DialogFragment中
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok, //字符串资源为常量OK
new DialogInterface.OnClickListener() { //此处的监听器后面有解释
@Override
public void onClick(DialogInterface dialog, int which) {
int year = mDatePicker.getYear();
int month = mDatePicker.getMonth();
int day = mDatePicker.getDayOfMonth();
Date date = new GregorianCalendar(year, month, day).getTime();
sendResult(Activity.RESULT_OK, date);
}
})
.create();
fragment间数据的传递
- 分为去和回:
- 去:
- fragment中的数据传给另一子fragment时,只要利用Fragment Argument,然后通过getArgument获取内容。
public static DatePickerFragment newInstance(Date date){
Bundle args = new Bundle();
args.putSerializable(ARG_DATE, date);
DatePickerFragment fragment = new DatePickerFragment();
fragment.setArguments(args);
return fragment;
}
- 由一个fragment调用另一个fragment需要找到FragmentManager
- 创建的子fragment需要设置当前fragment 为目标fragment。
- 创建的子fragment实例调用
show()
方法。
show(fm, String)
自动创建并提交事物。String 类型的键值对,进行标志。show(FragmentTrasaction, String)
自己负责创建并提交事物
mDateButton.setOnClickListener(new View.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); //第二个参数是在fragment队列中dialog的唯一tag常量标志。
}
});
- 回 :
当需要子fragment响应且返回数据时,就需要重写onActivityResult()
方法,有如下几点。
- 在上面的AlertDialog.Builider 点击监听器中获取相关Intent和结果代码。
- 通过调用
getTargetFragment().onActivityResult(getTargetRequestCode(), resultCode, intent);
调用父类fragment的onActivityResult方法,返回数据- 解析Intent并设置
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);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode != Activity.RESULT_OK) return;
if(requestCode == REQUEST_DATE){
Date date = (Date) data
.getSerializableExtra((DatePickerFragment.EXTRA_DATE));
mCrime.setDate(date);
updateDate();
}
}
相关小记
- 使用fm管理对话框,可以更灵活的显示对话框。若不使用,如果旋转设备,单独使用的AlertDialog会消失。而具有ID属性的视图可以保存运行状态。
DatePicker
对象的初始化需将Date形式的数据化为整数形式的 年月日,并将其初始化。
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);
View v = LayoutInflater.from(getActivity())
.inflate(R.layout.dialog_date, null);
mDatePicker = v.findViewById(R.id.dialog_date_picker);
mDatePicker.init(year, month, day, null);
- 将整数形式的数据转化为Date形式
int year = mDatePicker.getYear();
int month = mDatePicker.getMonth();
int day = mDatePicker.getDayOfMonth();
Date date = new GregorianCalendar(year, month, day).getTime();
- 可选择覆盖
DialogFragment.onCreateView()
方法,用于设置全屏fragment,以实现不同设备上的信息显示。
挑战练习
- 添加TImePickFragment
跟DatePickerFragment
没多大区别
package com.bignerdranch.andriod.criminalintent;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TimePicker;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class TimePickerFragment extends DialogFragment {
private static final String ARG_TIME = "time";
public static final String EXTRA_TIME =
"com.bignerdranch.andriod.criminalintent.time";
private TimePicker mTimePicker;
public static TimePickerFragment newInstance(Date time) {
Bundle bundle = new Bundle();
bundle.putSerializable(ARG_TIME, time);
TimePickerFragment fragment = new TimePickerFragment();
fragment.setArguments(bundle);
return fragment;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Date time = (Date) getArguments().getSerializable(ARG_TIME);
Calendar calendar = Calendar.getInstance();
calendar.setTime(time);
final int year = calendar.get(Calendar.YEAR);
final int month = calendar.get(Calendar.MONTH);
final int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
View v = LayoutInflater.from(getActivity())
.inflate(R.layout.fragment_time_picker, null);
mTimePicker = v.findViewById(R.id.dialog_time_picker);
mTimePicker.setCurrentHour(hour);
mTimePicker.setCurrentMinute(minute);
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.time_picker_title)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int hour = mTimePicker.getCurrentHour();
int minute = mTimePicker.getCurrentMinute();
Date time = new GregorianCalendar(year, month, day, hour, minute)
.getTime();
sendResult(Activity.RESULT_OK, time);
}
})
.create();
}
private void sendResult(int resultOk, Date time) {
if(getTargetFragment() == null) return;
Intent intent = new Intent();
intent.putExtra(EXTRA_TIME, time);
getTargetFragment().onActivityResult(getTargetRequestCode(), resultOk, intent);
}
}
- 挑战练习:实现响应式 DialogFragment
- 17章中实现了双版面以后, 传给CrimeFragment启动模式
@Override
public void onCrimeSelected(Crime crime) {
//手机模式
if (findViewById(R.id.detail_fragment_container) == null) {
Intent intent = CrimePagerActivity
.newIntent(this, crime.getUUID());
startActivity(intent);
} else {
//平板模式
CrimeFragment fragment = CrimeFragment
.newInstance(crime.getUUID(), false); //传给CrimeFragment打开的模式
getSupportFragmentManager().beginTransaction()
.replace(R.id.detail_fragment_container, fragment)
.commit();
}
}
//在ViewPager中
mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager,
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
@NonNull
@Override
public Fragment getItem(int position) {
Crime crime = mCrimes.get(position);
return CrimeFragment.newInstance(crime.getUUID(), true); //手机模式
}
@Override
public int getCount() {
return mCrimes.size();
}
});
- 取出以后判断启动方式
//CrimeFragment.java中
mode = (boolean) getArguments().getSerializable(ARG_MODE);
public void calendarMode(Crime crime){
if (mode){
Intent intent = DatePickerActivity
.newIntent(getActivity(), crime.getUUID());
startActivityForResult(intent, REQUEST_DATE);
}else {
datePickerFragment = DatePickerFragment.newInstance(crime.getDate());
datePickerFragment.setTargetFragment(CrimeFragment.this, REQUEST_DATE);
datePickerFragment.show(fragmentManager, DIALOG_DATE);
}
}
//实现DatePickerFragment的回调, 移除DatePickerFragment
@Override
public void removeCalendar() {
fragmentManager.beginTransaction().remove(datePickerFragment).commit();
}
- 点击确定按钮后
//DatePickerFragment中
public void sendResulet(int resultCode, Date date) {
Intent intent = new Intent();
intent.putExtra(EXTRA_DATE, date);
if (getTargetFragment() == null && getActivity() != null) {
getActivity().setResult(resultCode, intent);
getActivity().finish();
} else if (getTargetFragment() != null && getActivity() != null) {
getTargetFragment()
.onActivityResult(getTargetRequestCode(), resultCode, intent);
if (mCallback != null) {
mCallback.removeCalendar();
}
}
}
public interface Callbacks {
void removeCalendar();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (getTargetFragment() != null) {
mCallback = (Callbacks) getTargetFragment();
}
}
@Override
public void onDetach() {
super.onDetach();
mCallback = null;
}