安卓-用户界面-对话框

来源:互联网 发布:sql数据库删除表 编辑:程序博客网 时间:2024/06/05 18:19

这两天在看安卓源码有关对话框的API,把自己学到的一些东西来分享给大家!


先扯一些概念上的东西吧!

对话框是提示用户作出决定或输入额外信息的小窗口。 对话框不会填充屏幕,通常用于需要用户采取行动才能继续执行的模式事件。

以上内容来源于官方介绍。


一、先来介绍一下对话框的基类及其子类:

Dialog 类是对话框的基类,但您应该避免直接实例化 Dialog,而是使用下列子类之一:

AlertDialog

此对话框可显示标题、最多三个按钮、可选择项列表或自定义布局。
DatePickerDialog 或 TimePickerDialog
此对话框带有允许用户选择日期或时间的预定义 UI。
二、创建对话框的片段

public class FireMissilesDialogFragment extends DialogFragment {    @Override    public Dialog onCreateDialog(Bundle savedInstanceState) {        // Use the Builder class for convenient dialog construction        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) {                       // FIRE ZE MISSILES!                   }               })               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {                   public void onClick(DialogInterface dialog, int id) {                       // User cancelled the dialog                   }               });        // Create the AlertDialog object and return it        return builder.create();    }}
当你需要弹出一个对话框时,只需创建该类的实例对象,然后调用它的show()方法即可!   例如:
FireMissilesDialogFragment dialog = new FireMisslesDialogFragent();
dialog.show(getFragmentManager(), "dialog");

以上代码可以添加在一个按钮的点击事件里,点击按钮后就会弹出这个对话框!

二、构建提醒对话框

  1. 标题

    这是可选项,只应在内容区域被详细消息、列表或自定义布局占据时使用。 如需陈述的是一条简单消息或问题,则不需要标题。

  2. 内容区域

    它可以显示消息、列表或其他自定义布局。

  3. 操作按钮

    对话框中的操作按钮不应超过三个。

上代码:

// 1. Instantiate an AlertDialog.Builder with its constructorAlertDialog.Builder builder = new AlertDialog.Builder(getActivity());// 2. Chain together various setter methods to set the dialog characteristicsbuilder.setMessage(R.string.dialog_message)       .setTitle(R.string.dialog_title);
注意:此时创建的对话框并不能产生操作按钮,若要出现按钮必须添加下面的代码:

// 3. Add the buttonsbuilder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {           public void onClick(DialogInterface dialog, int id) {               // User clicked OK button           }       });builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {           public void onClick(DialogInterface dialog, int id) {               // User cancelled the dialog           }       });// Set other dialog properties...// 4.Create the AlertDialogAlertDialog dialog = builder.create();
注意:上述关于按钮的操作只给出了两个,另一个中性的按钮并未设置。(其实用的也不多嘛)


接下来我们来进行对内容区域中添加列表的功能进行介绍

我们通常通过 AlertDialog API 提供的三种列表来实现这一功能:

  • 传统单选列表
  • 永久性单选列表(单选按钮)
  • 永久性多选列表(复选框)
传统的单选列表
@Overridepublic 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) {               // The 'which' argument contains the index position               // of the selected item           }    });    return builder.create();}

要想指定列表项,请调用setItems() 来传递一个数组。或者,您也可以使用 setAdapter() 指定一个列表。 这样一来,您就可以使用 ListAdapter 以动态数据(如来自数据库的数据)支持列表。

如果您选择通过 ListAdapter 支持列表,请务必使用 Loader,以便内容以异步方式加载。

但是上述做出来的列表不能用手触碰,否则对话框会消失!如果想做到用手触碰列表不消失,那么就改用我下面的代码吧!

@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {    mSelectedItems = new ArrayList();  // Where we track the selected items    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());    // Set the dialog title    builder.setTitle(R.string.pick_toppings)    // Specify the list array, the items to be selected by default (null for none),    // and the listener through which to receive callbacks when items are selected           .setMultiChoiceItems(R.array.toppings, null,                      new DialogInterface.OnMultiChoiceClickListener() {               @Override               public void onClick(DialogInterface dialog, int which,                       boolean isChecked) {                   if (isChecked) {                       // If the user checked the item, add it to the selected items                       mSelectedItems.add(which);                   } else if (mSelectedItems.contains(which)) {                       // Else, if the item is already in the array, remove it                       mSelectedItems.remove(Integer.valueOf(which));                   }               }           })    // Set the action buttons           .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {               @Override               public void onClick(DialogInterface dialog, int id) {                   // User clicked OK, so save the mSelectedItems results somewhere                   // or return them to the component that opened the dialog                   ...               }           })           .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {               @Override               public void onClick(DialogInterface dialog, int id) {                   ...               }           });    return builder.create();}

注意:这一段代码可以用于复选框。

创建自定义布局


如果您想让对话框具有自定义布局,请创建一个布局,然后通过调用 AlertDialog.Builder 对象上的 setView() 将其添加到 AlertDialog

默认情况下,自定义布局会填充对话框窗口,但您仍然可以使用 AlertDialog.Builder 方法来添加按钮和标题。

一、布局文件的设置

res/layout/dialog_signin.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="wrap_content"    android:layout_height="wrap_content">    <ImageView        android:src="@drawable/header_logo"        android:layout_width="match_parent"        android:layout_height="64dp"        android:scaleType="center"        android:background="#FFFFBB33"        android:contentDescription="@string/app_name" />    <EditText        android:id="@+id/username"        android:inputType="textEmailAddress"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="16dp"        android:layout_marginLeft="4dp"        android:layout_marginRight="4dp"        android:layout_marginBottom="4dp"        android:hint="@string/username" />    <EditText        android:id="@+id/password"        android:inputType="textPassword"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginTop="4dp"        android:layout_marginLeft="4dp"        android:layout_marginRight="4dp"        android:layout_marginBottom="16dp"        android:fontFamily="sans-serif"        android:hint="@string/password"/></LinearLayout>
二、java代码

@Overridepublic Dialog onCreateDialog(Bundle savedInstanceState) {    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());    // Get the layout inflater    LayoutInflater inflater = getActivity().getLayoutInflater();    // Inflate and set the layout for the dialog    // Pass null as the parent view because its going in the dialog layout    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,而不是使用 Dialog API。 只需创建一个 Activity,并在 <activity> 清单文件元素中将其主题设置为 Theme.Holo.Dialog

<activity android:theme="@android:style/Theme.Holo.Dialog" >

就这么简单。Activity 现在会显示在一个对话框窗口中,而非全屏显示(我认为这样做并不是很好)

将事件传递回对话框的宿主


当用户触摸对话框的某个操作按钮或从列表中选择某一项时,您的 DialogFragment 可能会自行执行必要的操作,但通常您想将事件传递给打开该对话框的 Activity 或片段。 为此,请定义一个界面,为每种点击事件定义一种方法。然后在从该对话框接收操作事件的宿主组件中实现该界面。

例如,以下 DialogFragment 定义了一个界面,通过该界面将事件传回给宿主 Activity:

public class NoticeDialogFragment extends DialogFragment {    /* The activity that creates an instance of this dialog fragment must     * implement this interface in order to receive event callbacks.     * Each method passes the DialogFragment in case the host needs to query it. */    public interface NoticeDialogListener {        public void onDialogPositiveClick(DialogFragment dialog);        public void onDialogNegativeClick(DialogFragment dialog);    }    // Use this instance of the interface to deliver action events    NoticeDialogListener mListener;    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener    @Override    public void onAttach(Activity activity) {        super.onAttach(activity);        // Verify that the host activity implements the callback interface        try {            // Instantiate the NoticeDialogListener so we can send events to the host            mListener = (NoticeDialogListener) activity;        } catch (ClassCastException e) {            // The activity doesn't implement the interface, throw exception            throw new ClassCastException(activity.toString()                    + " must implement NoticeDialogListener");        }    }    ...}

对话框的宿主 Activity 会通过对话框片段的构造函数创建一个对话框实例,并通过实现的 NoticeDialogListener 界面接收对话框的事件:

public class MainActivity extends FragmentActivity                          implements NoticeDialogFragment.NoticeDialogListener{    ...    public void showNoticeDialog() {        // Create an instance of the dialog fragment and show it        DialogFragment dialog = new NoticeDialogFragment();        dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");    }    // The dialog fragment receives a reference to this Activity through the    // Fragment.onAttach() callback, which it uses to call the following methods    // defined by the NoticeDialogFragment.NoticeDialogListener interface    @Override    public void onDialogPositiveClick(DialogFragment dialog) {        // User touched the dialog's positive button        ...    }    @Override    public void onDialogNegativeClick(DialogFragment dialog) {        // User touched the dialog's negative button        ...    }}

由于宿主 Activity 会实现 NoticeDialogListener—由以上显示的 onAttach() 回调方法强制执行 — 因此对话框片段可以使用界面回调方法向 Activity 传递点击事件:

public class NoticeDialogFragment extends DialogFragment {    ...    @Override    public Dialog onCreateDialog(Bundle savedInstanceState) {        // Build the dialog and set up the button click handlers        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) {                       // Send the positive button event back to the host activity                       mListener.onDialogPositiveClick(NoticeDialogFragment.this);                   }               })               .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {                   public void onClick(DialogInterface dialog, int id) {                       // Send the negative button event back to the host activity                       mListener.onDialogNegativeClick(NoticeDialogFragment.this);                   }               });        return builder.create();    }}

显示对话框


如果您想显示对话框,请创建一个 DialogFragment 实例并调用 show(),以传递对话框片段的 FragmentManager 和标记名称。

您可以通过从 FragmentActivity 调用 getSupportFragmentManager() 或从 Fragment 调用 getFragmentManager() 来获取 FragmentManager。例如:

public void confirmFireMissiles() {    DialogFragment newFragment = new FireMissilesDialogFragment();    newFragment.show(getSupportFragmentManager(), "missiles");}

第二个参数 "missiles" 是系统用于保存片段状态并在必要时进行恢复的唯一标记名称。 该标记还允许您通过调用 findFragmentByTag() 获取片段的句柄。

全屏显示对话框或将其显示为嵌入式片段


您可能采用以下 UI 设计:您想让一部分 UI 在某些情况下显示为对话框,但在其他情况下全屏显示或显示为嵌入式片段(也许取决于设备使用大屏幕还是小屏幕)。DialogFragment 类便具有这种灵活性,因为它仍然可以充当嵌入式 Fragment

但在这种情况下,您不能使用 AlertDialog.Builder 或其他 Dialog 对象来构建对话框。如果您想让 DialogFragment 具有嵌入能力,则必须在布局中定义对话框的 UI,然后在 onCreateView() 回调中加载布局。

以下示例 DialogFragment 可以显示为对话框或嵌入式片段(使用名为 purchase_items.xml 的布局):

public class CustomDialogFragment extends DialogFragment {    /** The system calls this to get the DialogFragment's layout, regardless        of whether it's being displayed as a dialog or an embedded fragment. */    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,            Bundle savedInstanceState) {        // Inflate the layout to use as dialog or embedded fragment        return inflater.inflate(R.layout.purchase_items, container, false);    }    /** The system calls this only when creating the layout in a dialog. */    @Override    public Dialog onCreateDialog(Bundle savedInstanceState) {        // The only reason you might override this method when using onCreateView() is        // to modify any dialog characteristics. For example, the dialog includes a        // title by default, but your custom layout might not need it. So here you can        // remove the dialog title, but you must call the superclass to get the Dialog.        Dialog dialog = super.onCreateDialog(savedInstanceState);        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);        return dialog;    }}

以下代码可根据屏幕尺寸决定将片段显示为对话框还是全屏 UI:

public void showDialog() {    FragmentManager fragmentManager = getSupportFragmentManager();    CustomDialogFragment newFragment = new CustomDialogFragment();    if (mIsLargeLayout) {        // The device is using a large layout, so show the fragment as a dialog        newFragment.show(fragmentManager, "dialog");    } else {        // The device is smaller, so show the fragment fullscreen        FragmentTransaction transaction = fragmentManager.beginTransaction();        // For a little polish, specify a transition animation        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);        // To make it fullscreen, use the 'content' root view as the container        // for the fragment, which is always the root view for the activity        transaction.add(android.R.id.content, newFragment)                   .addToBackStack(null).commit();    }}

如需了解有关执行片段事务的详细信息,请参阅片段指南。

在本示例中,mIsLargeLayout 布尔值指定当前设备是否应该使用应用的大布局设计(进而将此片段显示为对话框,而不是全屏显示)。 设置这种布尔值的最佳方法是声明一个布尔资源值,其中包含适用于不同屏幕尺寸的备用资源值。 例如,以下两个版本的布尔资源适用于不同的屏幕尺寸:

res/values/bools.xml

<!-- Default boolean values --><resources>    <bool name="large_layout">false</bool></resources>

res/values-large/bools.xml

<!-- Large screen boolean values --><resources>    <bool name="large_layout">true</bool></resources>

然后,您可以在 Activity 的 onCreate() 方法执行期间初始化 mIsLargeLayout 值:

boolean mIsLargeLayout;@Overridepublic void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    mIsLargeLayout = getResources().getBoolean(R.bool.large_layout);}

将 Activity 显示为大屏幕上的对话框

相对于在小屏幕上将对话框显示为全屏 UI,您可以通过在大屏幕上将 Activity 显示为对话框来达到相同的效果。您选择的方法取决于应用设计,但当应用已经针对小屏幕进行设计,而您想要通过将短生存期 Activity 显示为对话框来改善平板电脑体验时,将 Activity 显示为对话框往往很有帮助。

要想仅在大屏幕上将 Activity 显示为对话框,请将 Theme.Holo.DialogWhenLarge 主题应用于 <activity> 清单文件元素:

<activity android:theme="@android:style/Theme.Holo.DialogWhenLarge" >

如需了解有关通过主题设置 Activity 样式的详细信息,请参阅样式和主题指南。

清除对话框


当用户触摸使用 AlertDialog.Builder 创建的任何操作按钮时,系统会为您清除对话框。

系统还会在用户触摸某个对话框列表项时清除对话框,但列表使用单选按钮或复选框时除外。 否则,您可以通过在 DialogFragment 上调用dismiss() 来手动清除对话框。

如需在对话框消失时执行特定操作,则可以在您的 DialogFragment 中实现 onDismiss() 方法。

您还可以取消对话框。这是一个特殊事件,它表示用户显式离开对话框,而不完成任务。 如果用户按“返回”按钮,触摸对话框区域外部的屏幕,或者您在 Dialog 上显式调用 cancel()(例如,为了响应对话框中的“取消”按钮),就会发生这种情况。

如上例所示,您可以通过在您的 DialogFragment 类中实现onCancel() 来响应取消事件。

注:系统会在每个调用 onCancel() 回调的事件发生时立即调用 onDismiss()。不过,如果您调用 Dialog.dismiss() 或DialogFragment.dismiss(),系统会调用 onDismiss(),而不会调用 onCancel()。因此,当用户在对话框中按“肯定”按钮,从视图中移除对话框时,您通常应该调用 dismiss()




1 0
原创粉丝点击