对话框是人机交互的有力工具,Android自带了几个常用的对话框,包括AlertDialog提示对话框、ProgressDialog进度对话框、DatePickerDialog日期选择对话框、TimePickerDialog时间选择对话框等等。其中最常用的是AlertDialog,而且需要自定义对话框的时候,多半也是在AlertDialog.Builder基础上集成其他的控件,具体参见《Android开发笔记(六十六)自定义对话框》。

ProgressDialog也比较常用,在系统加载信息或者等待其他事情时,都可能需要显示ProgressDialog。相比之下,DatePickerDialog和TimePickerDialog用的不多,因为这两个对话框上的文字依赖于系统的语言设置,如果系统默认语言是英文,DatePickerDialog和TimePickerDialog上的文字也是英文,而且还无法设置为中文;另一个原因是这两个对话框的布局和风格无法自定义,如果想加上别的提示信息,就得自己重写代码了。

接下来我们就使用AlertDialog来重写日期和时间对话框。首先要提供日期对话框和时间对话框的布局文件,例如R.layout.dialog_format_date和R.layout.dialog_format_time,布局文件中需分别集成DatePicker和TimePicker控件。然后分别初始化DatePicker和TimePicker对象,分别设置当前日期与当前时间。接着创建一个AlertDialog.Builder对象,在该Builder对象中嵌入布局视图,并设置标题、确定按钮、取消按钮。最后还要提供一个回调接口,用于主页面上处理日期和时间的选择事件,同时在确定按钮的点击事件中要触发该回调接口的方法。下面是重写后的日期和时间对话框的代码:

```java

private void showDateAndTimeDialog() {

// 提供日期对话框和时间对话框的布局文件

final int dateId = R.layout.dialog_format_date;

final int timeId = R.layout.dialog_format_time;

// 分别初始化DatePicker和TimePicker对象,并设置当前日期与当前时间

DatePicker datePicker = findViewById(R.id.date_picker);

TimePicker timePicker = findViewById(R.id.time_picker);

Calendar calendar = Calendar.getInstance();

datePicker.init(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), new DatePicker.OnDateChangedListener() {

@Override

public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {

// 在此处更新日期选择器的显示内容

}

});

timePicker.setCurrentHour(calendar.get(Calendar.HOUR_OF_DAY));

timePicker.setCurrentMinute(calendar.get(Calendar.MINUTE));

timePicker.setCurrentSecond(calendar.get(Calendar.SECOND));

// 创建AlertDialog.Builder对象,并嵌入布局视图

AlertDialog.Builder builder = new AlertDialog.Builder(this);

LayoutInflater inflater = getLayoutInflater();

View view = inflater.inflate(dateId, null);

builder.setView(view);

// 设置标题、确定按钮、取消按钮等属性

builder.setTitle("选择日期和时间")

.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

// 在此处处理日期和时间的选择事件

}

})

.setNegativeButton("取消", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {}

});

// 将自定义的布局添加到AlertDialog中

ViewGroup contentView = (ViewGroup) builder.getView().findViewById(android.R.id.content);

LinearLayout dateLayout = contentView.findViewById(R.id.date_layout);

LinearLayout timeLayout = contentView.findViewById(R.id.time_layout);

TextView dateText = dateLayout.findViewById(R.id.date_text);

TextView timeText = timeLayout.findViewById(R.id.time_text);

int selectedDate = datePicker.getDayOfMonth();

int selectedYear = datePicker.getYear();

int selectedMonth = datePicker.getMonth();

int selectedHour = timePicker.getCurrentHour();

int selectedMinute = timePicker

以下是重构后的代码:

```java

import java.util.Calendar;

import java.util.Date;

import android.annotation.SuppressLint;

import android.app.Activity;

import android.app.AlertDialog;

import android.content.Context;

import android.content.DialogInterface;

import android.view.View;

import android.widget.DatePicker;

import android.widget.TimePicker;

import com.example.exmfiledialog.R;

import com.example.exmfiledialog.util.DateUtil;

@SuppressLint("InflateParams")

public class CalendarDialog {

private Context mContext;

private CalendarCallbacks mCallbacks;

public CalendarDialog(Context context) {

mContext = context;

}

public interface CalendarCallbacks {

void onDateSelect(String date);

void onTimeSelect(String time);

}

public void setCallbacks(CalendarCallbacks callbacks) {

mCallbacks = callbacks;

}

public void showDateDialog() {

AlertDialog.Builder builder = new AlertDialog.Builder(mContext);

View view = ((Activity) mContext).getLayoutInflater().inflate(R.layout.dialog_format_date, null);

final DatePicker datePicker = (DatePicker) view.findViewById(R.id.date_picker);

Calendar calendar = Calendar.getInstance();

// 初始化时间

calendar.setTime(new Date());

datePicker.init(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), null);

builder.setView(view);

builder.setIcon(R.drawable.ic_about);

builder.setTitle("设置日期信息");

builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

mCallbacks.onDateSelect(DateUtil.getDate(datePicker.getYear(), datePicker.getMonth() + 1, datePicker.getDayOfMonth()));

dialog.cancel();

}

});

builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

dialog.cancel();

}

});

builder.create().show();

}

public void showTimeDialog() {

AlertDialog.Builder builder = new AlertDialog.Builder(mContext);

View view = ((Activity) mContext).getLayoutInflater().inflate(R.layout.dialog_format_time, null);

final TimePicker timePicker = (TimePicker) view.findViewById(R.id.time_picker);

Calendar calendar = Calendar.getInstance();

calendar.setTime(new Date());

timePicker.setIs24HourView(true);

timePicker.setCurrentHour(calendar.get(Calendar.HOUR_OF_DAY));

timePicker.setCurrentMinute(calendar.get(Calendar

以下是对话框的调用示例代码的关键片段,它演示了如何在Android应用中创建一个信息确认对话框:

```java

import com.example.exmfiledialog.widget.CalendarDialog;

import com.example.exmfiledialog.widget.CalendarDialog.CalendarCallbacks;

public class MainActivity extends Activity implements OnClickListener, CalendarCallbacks {

@Override

public void onClick(View v) {

if (v.getId() == R.id.btn_date) {

CalendarDialog dialog = new CalendarDialog(this);

dialog.setCallbacks(this);

dialog.showDateDialog();

} else if (v.getId() == R.id.btn_time) {

CalendarDialog dialog = new CalendarDialog(this);

dialog.setCallbacks(this);

dialog.showTimeDialog();

}

}

@Override

public void onDateSelect(String date) {

Toast.makeText(this, "您选择的日期是:" + DateUtil.getDateCN(date), Toast.LENGTH_LONG).show();

}

@Override

public void onTimeSelect(String time) {

Toast.makeText(this, "您选择的时间是:" + DateUtil.getTimeCN(time), Toast.LENGTH_LONG).show();

}

}

```

在这段代码中,我们首先导入所需的库。接着,我们定义了一个名为`MainActivity`的类,该类实现了`OnClickListener`和`CalendarCallbacks`接口。当用户点击按钮时,会根据按钮的ID来显示日期或时间选择对话框。当用户选择完日期或时间后,会弹出一个Toast消息通知用户所选的日期和时间。

虽然AlertDialog可以用于自定义对话框,但实际上它内部的Builder只是用来集成的,并且存在一些缺陷,例如调用时需要手动设置回调接口,无法管理生命周期等。要实现一个更完善的对话框,需要在自定义对话框时继承DialogFragment类。下面通过一个简单的提示对话框进行说明,该对话框主要用于显示一段文字,然后由用户选择“确定”或“取消”。

首先是ConfirmDialogFragment的初始化方法,这里采用Fragment类通用的newInstance函数。在newInstance中创建一个实例,并传入所需的参数信息,如标题、内容等字段。接下来,在该实例加入到activity页面时(onAttach方法),设置回调接口,并从getArguments()中取出参数信息。然后重写onCreateDialog方法,往对话框界面上添加具体的视图布局。这里的视图布局可以从xml文件中获取,也可以在代码中逐个添加。onCreateDialog方法后面当然要依例添加AlertDialog.Builder对象,依次设置标题、内容、图标、确定按钮、取消按钮等元素,其中确定按钮的点击事件需要调用回调接口的处理方法。最后,在主页面中调用自定义的提示对话框。

自定义提示对话框的代码如下:

```java

import java.util.Map;

import android.app.Activity;

import android.app.AlertDialog;

import android.app.Dialog;

import android.app.DialogFragment;

import android.content.DialogInterface;

import android.os.Bundle;

import android.view.ViewGroup;

import android.widget.LinearLayout;

public class ConfirmDialogFragment extends DialogFragment {

private static final String TAG = "ConfirmDialogFragment";

private Map mMapParam;

private ConfirmCallbacks mCallbacks;

private LinearLayout mRoot;

private int mIconId;

private String mTitle;

private String mMessage;

public static ConfirmDialogFragment newInstance(int icon_id, String title, String message) {

ConfirmDialogFragment frag = new ConfirmDialogFragment();

Bundle args = new Bundle();

args.putInt("icon_id", icon_id);

args.putString("title", title);

args.putString("message", message);

frag.setArguments(args);

return frag;

}

@Override

public void onAttach(Activity activity) {

super.onAttach(activity);

if (!(activity instanceof ConfirmCallbacks)) {

throw new IllegalStateException("Activity must implement fragment's callbacks.");

}

mCallbacks = (ConfirmCallbacks) activity;

mIconId = getArguments().getInt("icon_id");

mTitle = getArguments().getString("title");

mMessage = getArguments().getString("message");

}

public void setParam(Map mapParam) {

mMapParam = mapParam;

}

public interface ConfirmCallbacks {

public void onConfirmSelect(Map map_param);

}

@Override

public AlertDialog onCreateDialog(BundlesavedInstanceState) throws Exception{

LinearLayout.LayoutParams rootLayout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT,0.0F);

mRoot = new LinearLayout(getActivity());

mRoot.setOrientation(LinearLayout.VERTICAL);

mRoot.setLayoutParams(rootLayout);

Builder popupBuilder = new AlertDialog.Builder(getActivity());

popupBuilder.setView(mRoot);

if (mIconId > 0){

popupBuilder.setIcon(mIconId);

}

popupBuilder.setTitle(mTitle);

popupBuilder.setMessage(mMessage);

popupBuilder.setPositiveButton("确定", new OnClickListener() {{ }});

popupBuilder.setNegativeButton("取消", new OnClickListener() {{ }});

return popupBuilder.create(); } } }

```

主页面的调用代码如下:

```java

private void showConfirmDialog() {

ConfirmDialogFragment fsf = ConfirmDialogFragment.newInstance(

R.drawable.ic_about, "吃货来了", "您是否想吃海鲜大餐?");

Map map_param = new HashMap();

map_param.put("address", "台北");

fsf.setParam(map_param);

fsf.show(getFragmentManager(), "");

}

```

接下来是文件打开和文件保存对话框的实现。文件对话框是从DialogFragment类继承而来,主要步骤与ConfirmDialogFragment大同小异,其主要难点在于文件和文件夹的处理。另外,文件(夹)列表需要用ListView来展示,所以得补充ListView必须的适配器与监听器,适配器ArrayAdapter用于展示文件和文件夹列表,监听器用于响应文件项的点击事件。当然不要忘了在主页面的回调方法中对选定文件做具体处理,文件打开之后要如何读取数据,又要如何把内存中的数据保存到文件中。下面是文件打开对话框与文件保存对话框的页面截图: