一、dialog
对话框是提示用户做出决定或输入额外信息的小窗口。
Dialog类是对话框的基类,但应避免直接实例化Dialog,而应选择以下三种:
AlertDialog:可显示标题、最多三个按钮、可选则列表项或自定义布局;(直接在此使用Edittext可能无法输入文本,需要自定义实现Dialog)
DatePickerDialog:选择日期的预定义UI;
TimePickerDialog:选择时间的预定义UI。
建议使用DialogFragment作为对话框的容器。其提供创建对话框和管理其外观所需的所有控件,而非调用Dialog对象上的方法。
使用DialogFragment管理对话框可确保它能正确处理声明周期事件,如用户按“返回”按钮或旋转屏幕时。此外,该类还允许将对话框的UI作为嵌入式组件在较大UI中重复使用。
下面的几个例子都是使用DialogFragment作为容器。
二、AlertDialog
1.对话框Fragment
public class FireMissilesDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// 使用Builder方便的构建dialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.dialog_fire_missiles)
.setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// 确定
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// 取消
}
});
// 创建alertdialog
return builder.create();
}
}
此时,可以创建该fragment实例并调用show()方法显示dialog。
2.提醒对话框
对话框有三个区域:标题(可选)、内容区域(可以显示消息、列表、自定义布局)、操作按钮(不应超过三个)。
1)添加按钮:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// 添加按钮
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// 确定
}
});
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// 取消
}
});
// 其他属性设置
...
// 创建dialog
AlertDialog dialog = builder.create();
2)添加单选列表
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.pick_color)
.setItems(R.array.colors_array, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// which对应item的下标
}
});
return builder.create();
}
3)永久性多选或单选列表
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mSelectedItems = new ArrayList(); // 选中的列表
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// 标题
builder.setTitle(R.string.pick_toppings)
// 指定列表,默认选中的item(没有默认则为null),item选中回调
.setMultiChoiceItems(R.array.toppings, null,
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which,
boolean isChecked) {
if (isChecked) {
// 如果选中item,添加到选中列表
mSelectedItems.add(which);
} else if (mSelectedItems.contains(which)) {
// 如果item已经存在于选中列表中,移除
mSelectedItems.remove(Integer.valueOf(which));
}
}
})
// 设置按钮点击事件
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
// 点击确定按钮,可以回调打开dialog的组件
...
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
...
}
});
return builder.create();
}
单选使用setSingleChoiceItems()。
4)创建自定义布局
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// 获取LayoutInflater
LayoutInflater inflater = getActivity().getLayoutInflater();
// 加载并设置布局
// 第二参数传null作为父视图,因为要在dialog布局中使用
builder.setView(inflater.inflate(R.layout.dialog_signin, null))
// Add action buttons
.setPositiveButton(R.string.signin, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
// sign in the user ...
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
LoginDialogFragment.this.getDialog().cancel();
}
});
return builder.create();
}
提示:如果想自定义对话框,可以对话框形式显示Activity,在清单中设置其主体为Theme.Holo.Dialog。
三、TimePickerDialog
public static class TimePickerFragment extends DialogFragment
implements TimePickerDialog.OnTimeSetListener {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// 使用当前时间做默认值
final Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
// 创建新TimePickerDialog实例并返回
return new TimePickerDialog(getActivity(), this, hour, minute,
DateFormat.is24HourFormat(getActivity()));
}
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// 当用户选择时间之后做一些操作
}
}
只要调用DialogFragment的show()方法即可显示。
四、DatePickerDialog
public static class DatePickerFragment extends DialogFragment
implements DatePickerDialog.OnDateSetListener {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// 当前日期为默认日期
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
//创建DatePickerDialog实例并返回
return new DatePickerDialog(getActivity(), this, year, month, day);
}
public void onDateSet(DatePicker view, int year, int month, int day) {
// 用户选择日期后做的操作
}
}
只要调用DialogFragment的show()方法即可显示。
五、将事件传递回对话框的宿主
public class NoticeDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// 构建dialog并且设置按钮点击事件
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.dialog_fire_missiles)
.setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// 发送确定事件回调给宿主activity
mListener.onDialogPositiveClick(NoticeDialogFragment.this);
}
})
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// 发送取消事件回调给宿主activity
mListener.onDialogNegativeClick(NoticeDialogFragment.this);
}
});
return builder.create();
}
// 创建该DialogFragment的activity实例必须实现这个接口,以便接收事件回调。
public interface NoticeDialogListener {
public void onDialogPositiveClick(DialogFragment dialog);
public void onDialogNegativeClick(DialogFragment dialog);
}
// 使用该接口示例传递事件
NoticeDialogListener mListener;
// 重写Fragment.onAttach()方法,将activity装换为回调接口
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// 检测activity是否实现了回调接口
try {
// 转换成回调接口,以便发送事件到宿主
mListener = (NoticeDialogListener) activity;
} catch (ClassCastException e) {
// 如果activity没有实现回调接口,抛出异常
throw new ClassCastException(activity.toString() + " must implement NoticeDialogListener");
}
}
...
}
宿主activity实现:
public class MainActivity extends FragmentActivity
implements NoticeDialogFragment.NoticeDialogListener{
...
public void showNoticeDialog() {
// 创建dialog fragment实例并显示
DialogFragment dialog = new NoticeDialogFragment();
dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
}
// dialog fragment获得activity的引用通过onAttach()方法
@Override
public void onDialogPositiveClick(DialogFragment dialog) {
// 确定回调
...
}
@Override
public void onDialogNegativeClick(DialogFragment dialog) {
// 取消回调
...
}
}
六、对话框消除
点击dialog的任何按钮,系统会清除对话框。对话框列表项被单击时,也会清除。但使用单选按钮或复选按钮时除外。可以通过DialogFragment的dismiss()方法来手动清除对话框。
如果要在对话框消失时执行特定操作,可以实现DialogFragment中的onDismiss()回调。
注意,系统会在每个调用onCancel()回调事件时调用onDismiss()。不过,如果调用了Dialog.dismiss()或DialogFragment.dismiss(),系统会调用onDismiss()但不会调用onCancel()。因此当点击确定而移除对话框时,通常一个调用dismiss();
七、dialog位置
这块是自己补上的。开发中常遇到一些指定dialog位置的需求。此时,我们可以设置其window的x,y偏移量等属性。
Window window = breedLogResultDialog.getWindow();
if (window != null) {
WindowManager.LayoutParams lp = window.getAttributes();
lp.x = 0;
lp.y = -100; // 向上偏移100px
window.setAttributes(lp);
}