当前位置: 代码迷 >> Android >> Android惯用UI之AlertDialog
  详细解决方案

Android惯用UI之AlertDialog

热度:134   发布时间:2016-04-24 11:17:06.0
Android常用UI之AlertDialog

转载请注明出处:http://blog.csdn.net/h_zhang/article/details/51068024

任何有关GUI编程都少不了对话框的使用,Android也是如此。本篇文章就对Android中AlertDialog的使用方法进行总结。那么什么时候需要使用AlertDialog呢?一般当你的APP询问用户是否做一个重要的决定的时候,或者从用户获取输入数据的时候可以使用AlertDialog。使用AlertDialog好处就是可以使上述场景在同一Activity中进行,而不需要开启一个新的Activity。下图就是官方提供一个完整的AlertDialog样式:


这里写图片描述

如图所示,一个AlertDialog共有三个部分组成:

  1. Titile
    对于AlertDialog来说,Title是一个可选的部分,你可以根据自己的场景需求来决定是否需要Title
  2. Content Area
    这个部分可以显示文本、列表、或者自定义的布局
  3. Action Buttons
    一个AlertDialog中Action Buttons的数量最多为三个

创建一个AlertDialog

创建一个AlertDialog之前,你需要先创建出AlertDialog.Builder对象,AlertDialog.Builder是AlertDialog的一个内部类,专门负责建造AlertDialog。很明显,AlertDialog使用的是建造者设计模式。创建语法如下:

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

接着你需要使用builder对象设置“确定”和“取消”按钮,那么语法如下所示:

builder.setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener);builder.setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener);

除了上述方法,AlertDialog.Builder还提供很多方法用于建造AlertDialog。下表列出了一些常用方法:

方法定义 方法说明
setIcon(int iconId) 设置对话框的图标
setCancelable(boolean cancelable) 设置对话框是否可取消
setTitle(CharSequence title) 设置对话框的标题
setMessage(CharSequence message) 设置对话框主体内容

建造完AlertDialog后,就可以显示了。显示语法如下:

AlertDialog alertDialog = builder.create();alertDialog.show();

OK!这样就完成了一个最简单的AlertDialog创建和显示。


使用DialogFragment

Android开发团队在Android 3.0之后引入了DialogFragment,并建议开发者使用DialogFragment作为对话框的容器,而不要单独使用AlertDialog创建对话框。也就是说对话框的创建和显示由DialogFragment统一管理,不需要再调用Dialog对象中的方法。官方也解释了使用DialogFragment管理对话框的种种好处,那么我们也按照官方的建议来创建对话框。使用DialogFragment创建对话框的语法如下所示:

public class TestDialogFragment extends DialogFragment{    @Override    public Dialog onCreateDialog(Bundle savedInstanceState)    {        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());        builder.setMessage("删除此联系人?")                .setPositiveButton("删除", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                    }                })                .setNegativeButton("取消", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                    }                });        return builder.create();    }}

TestDialogFragment类继承自DialogFragment,然后重写onCreateDialog()方法,在该方法中利用AlertDialog.Builder类构建对话框。最后调用builder.create()创建对话框并返回。
好的,对话框创建成功之后,该如何显示呢?直接贴出Activity代码:

public class MainActivity extends AppCompatActivity{    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    public void alertDialog(View view)    {        DialogFragment dialogFragment = new TestDialogFragment();        dialogFragment.show(getFragmentManager(), "del");    }}

其中alertDialog(View view)是触摸按钮的回调函数,可以看到显示对话框就两行代码,首先new出TestDialogFragment实例,然后调用DialogFragment中的show()方法,这个方法需要两个参数,第一个参数是FragmentManager对象,通过getFragmentManager()获得;第二个参数是一个Tag,用来对对话框做唯一标识。虽然很简单还是贴一下运行效果:


这里写图片描述


列表对话框

Android提供了三种内容为列表的对话框,分别是:

  1. 传统列表对话框
  2. 单选列表对话框
  3. 多选列表对话框

下面就分别看一下他们的使用方法,以及显示效果;

传统列表对话框

微信中长按联系人就会弹出一个传统列表对话框,这里我也模仿微信来看一下传统列表对话框创建和显示效果:

public class TestDialogFragment extends DialogFragment{    private String[] items = new String[]{"标为未读", "置顶聊天", "删除该聊天"};    @Override    public Dialog onCreateDialog(Bundle savedInstanceState)    {        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());        builder.setItems(items, new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                        Toast.makeText(getActivity(), items[which], Toast.LENGTH_SHORT).show();                    }                });        return builder.create();    }}

可以看到传统列表对话框的创建使用AlertDialog.Builder中的setItems (CharSequence[] items, DialogInterface.OnClickListener listener)方法,该方法第一个参数是一个字符串数组,第二参数是点击监听器。由于列表占据了对话框的Content Area,所以我们不能再调用setMessage (CharSequence message)方法,但是可以调用setTitle (CharSequence title)方法为对话框设置title。传统列表对话框的运行效果如下:


这里写图片描述

单选列表对话框

单选列表对话框和传统列表对话框用法很类似。这里我就直接贴代码看效果;

public class TestDialogFragment extends DialogFragment{    private String[] items = new String[]{"男", "女", "不详"};    private int mWhich = 0;    @Override    public Dialog onCreateDialog(Bundle savedInstanceState)    {        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());        builder.setTitle("请选择性别")                .setSingleChoiceItems(items, mWhich, new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                        mWhich = which;                    }                })                .setPositiveButton("确定", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                        Toast.makeText(getActivity(), items[mWhich], Toast.LENGTH_SHORT).show();                    }                });        return builder.create();    }}

设置单选列表对话框使用setSingleChoiceItems (CharSequence[] items, int checkedItem, DialogInterface.OnClickListener listener)方法,第一个参数是一个字符串数组,第二个参数表示当前选中列表第几项(从0开始),第三个参数是监听器;下面看运行效果:


这里写图片描述

可以发现,传统列表对话框和单选列表对话框包括下面将讲到的多选列表对话框的一个最大的区别是:点击传统列表对话框的任意一个item,对话框就会被系统自动销毁;但是单选列表对话框中的item后,对话框仍然是显示的,所以需要提供的“确定”按钮,点击了“确定”按钮之后,对话框会被系统销毁;除了这个区别传统列表对话框和单选列表对话框还是非常相似的。

既然这么类似,那么我们在什么时候使用传统列表对话框?又该在什么时候使用单选列表对话框呢?其实,当我们需要显示用户上一次的选择,我们就可以使用单选列表对话框来显示用户上次做的选择,否则可以使用传统列表列表对话框。

多选列表对话框

举一反三,下面直接就来看多选列表对话框该如何使用:

public class TestDialogFragment extends DialogFragment{    private String[] items = new String[]{"游泳", "唱歌", "跳舞", "跑步"};    private List<Integer> mSelectedList = new ArrayList<Integer>();    @Override    public Dialog onCreateDialog(Bundle savedInstanceState)    {        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());        builder.setTitle("请选择爱好")                .setMultiChoiceItems(items, null, new DialogInterface.OnMultiChoiceClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which, boolean isChecked)                    {                        if(isChecked)                        {                            //添加到已选数组中                            mSelectedList.add(which);                        }else if(mSelectedList.contains(which)){                            //如果该项在已选数组中,删除它                            mSelectedList.remove(Integer.valueOf(which));                        }                    }                })                .setPositiveButton("确定", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                        StringBuilder sb = new StringBuilder();                        if(mSelectedList.size() > 0)                        {                            for (Integer i : mSelectedList)                            {                                sb.append(items[i]);                            }                            Toast.makeText(getActivity(), sb.toString(), Toast.LENGTH_SHORT).show();                        }                    }                })                .setNegativeButton("取消", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                    }                });        return builder.create();    }}

多选列表对话框使用setMultiChoiceItems (CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)方法来设置对话框的Content Area。同样,该方法第一个参数是一个字符串数组;第二个参数是一个布尔数组,用来记录默认选项,null表示没有默认项;第三个参数是一个监听器;代码中定义了一个mSelectedList 数组用于记录已选择的列表项的索引。程序运行效果如下所示:


这里写图片描述


自定义对话框的布局

如果我们想要自定义对话框的布局,我们可以使用AlertDialog.Builder类中的setView ()方法。默认情况下,我们自定义的布局会填充整个对话框窗口,我们仍然可以使用AlertDialog.Builder类中的方法设置title以及添加按钮。下面我们自定义一个登录对话框布局,并且仍然使用AlertDialog.Builder类中的方法为对话框添加按钮。

首先是布局文件 login.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="match_parent"              android:orientation="vertical">    <ImageView        android:layout_width="match_parent"        android:layout_height="64dp"        android:scaleType="fitCenter"        android:background="#bbb"        android:src="@drawable/logo"/>    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:hint="用户名/手机/邮箱"        android:layout_marginTop="16dp"        android:layout_marginLeft="4dp"        android:layout_marginRight="4dp"        android:layout_marginBottom="4dp"        />    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:fontFamily="sans-serif"        android:hint="密码"        android:inputType="textPassword"        android:layout_marginTop="4dp"        android:layout_marginLeft="4dp"        android:layout_marginRight="4dp"        android:layout_marginBottom="16dp"/></LinearLayout>

一个ImageView用于显示logo,两个EditText让用户输入用户名和密码。

下面是 TestDialogFragment.java 代码:

public class TestDialogFragment extends DialogFragment{    @Override    public Dialog onCreateDialog(Bundle savedInstanceState)    {        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());        LayoutInflater inflater = LayoutInflater.from(getActivity());         //设置自定义布局        builder.setView(inflater.inflate(R.layout.login, null))                .setPositiveButton("登录", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                    }                })                .setNegativeButton("取消", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                    }                });        return builder.create();    }}

首先使用LayoutInflater.from()获得LayoutInflater对象,然后利用LayoutInflater对象将布局文件解析成View对象,最后调用 builder.setView()方法将自定义布局设置到对话框。下面看程序运行效果:


这里写图片描述

可以看到,这里对话框中的布局使用的是自定义布局,但下面两个按钮仍然使用系统自带的按钮。当然,如果觉得系统提供的按钮太单调,我们也可以在布局文件中添加自定义的按钮。


对话框事件传递到Activity

通常我们启动一个AlertDialog来让用户做一个选择,或者接受用户输入信息。当用户结束完对话框操作(比如,点击了对话框按钮或者选择了列表中一个item),你很可能在DialogFragment中执行了一些逻辑操作。但是,也有很多情况,我们需要通知启动该对话框的Activity,Activity需要根据用户在对话框上操作来执行具体的逻辑。那么现在的问题就是:对话框中的点击事件如何传递给Activity呢?相信你已经猜到了。对,没错,就是利用接口回调机制。

首先,我们定义一个接口,并且在接口中定义一些事件响应函数;然后让具体的activity实现该接口;下面就是设置该接口,那么我们在哪里设置这个接口实例呢?下面看代码:

TestDialogFragment.java

public class TestDialogFragment extends DialogFragment{    //定义回调接口    public interface NoticeDialogListener    {        public void onDialogPositiveClick(DialogFragment dialog);        public void onDialogNegativiClick(DialogFragment dialog);    }    //定义接口成员变量    private NoticeDialogListener mListener;    @Override    public Dialog onCreateDialog(Bundle savedInstanceState)    {        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());        LayoutInflater inflater = LayoutInflater.from(getActivity());        builder.setTitle("事件传递")                .setMessage("通过接口回调的方式,将点击事件传递给Activity")                .setPositiveButton("确定", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                        mListener.onDialogPositiveClick(TestDialogFragment.this);                    }                })                .setNegativeButton("取消", new DialogInterface.OnClickListener()                {                    @Override                    public void onClick(DialogInterface dialog, int which)                    {                        mListener.onDialogNegativiClick(TestDialogFragment.this);                    }                });        return builder.create();    }    //在DialogFragment的onAttach(activity)生命周期函数中设置回调接口    @Override    public void onAttach(Activity activity)    {        super.onAttach(activity);        try        {            mListener = (NoticeDialogListener) activity;        } catch (ClassCastException e)        {            throw new ClassCastException(activity.toString()                    + "必须实现NoticeDialogListener接口");        }    }}

第4行,定义了一个内部接口NoticeDialogListener,第11行,使用该接口定义了一个成员变量也就是我们的回调接口,那么在哪里设置回调接口呢?第42行,我们在生命周期函数中onAttach()对回调接口进行设置,因为通过onAttach()函数我们可以拿到启动对话框的Activity,同时在第49行,如果Activity没有实现回调接口,我们就抛出异常,这样我们就成功对回调接口进行实例化。

下面看Activity代码,MainActivity.java:

public class MainActivity extends AppCompatActivity implements TestDialogFragment.NoticeDialogListener{    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    public void alertDialog(View view)    {        DialogFragment dialogFragment = new TestDialogFragment();        dialogFragment.show(getFragmentManager(), "del");    }    @Override    public void onDialogPositiveClick(DialogFragment dialog)    {        Toast.makeText(MainActivity.this, //                "Activity:onDialogPositiveClick()", //                Toast.LENGTH_SHORT).show();    }    @Override    public void onDialogNegativiClick(DialogFragment dialog)    {        Toast.makeText(MainActivity.this, //                "Activity:onDialogNegativiClick()", //                Toast.LENGTH_SHORT).show();    }}

OK!Activity代码还是那些,就多实现了TestDialogFragment.NoticeDialogListener接口。下面是程序运行效果:


这里写图片描述


对话框样式的Activity

我还可以将一个Activity以对话框形式展现,只要在AndroidManifest.xml中对Activity的theme进行设置即可,Android有很多对话框式主题供我们选择,下面看具体代码。

LoginActivity的布局文件,login.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="match_parent"              android:orientation="vertical">    <ImageView        android:layout_width="match_parent"        android:layout_height="64dp"        android:background="#bbb"        android:scaleType="fitCenter"        android:src="@drawable/logo"/>    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginBottom="4dp"        android:layout_marginLeft="4dp"        android:layout_marginRight="4dp"        android:layout_marginTop="16dp"        android:hint="用户名/手机/邮箱"        />    <EditText        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginBottom="16dp"        android:layout_marginLeft="4dp"        android:layout_marginRight="4dp"        android:layout_marginTop="4dp"        android:fontFamily="sans-serif"        android:hint="密码"        android:inputType="textPassword"/>    <Button        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:onClick="login"        android:text="登录"/></LinearLayout>

下面是LoginActivity代码,LoginActivity.java :

public class LoginActivity extends Activity{    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.login);    }    public void login(View view)    {        Toast.makeText(LoginActivity.this, "登录", Toast.LENGTH_SHORT).show();        finish();    }}

login()方法是“登录”按钮的回调函数,在里面我们就简单弹了一个Toast,然后finish掉Activity。下面是MainActivity代码,MainActivity.java :

public class MainActivity extends AppCompatActivity{    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    public void alertDialog(View view)    {        Intent intent = new Intent(MainActivity.this, LoginActivity.class);        startActivity(intent);    }}

相信大家都能看得懂,最后别忘了在AndroidManifest.xml中注册LoginActivity,并指定它的Theme为对话框样式:

<activity android:name=".LoginActivity"    android:theme="@android:style/Theme.Holo.Light.Dialog.NoActionBar.MinWidth"></activity>

下面就是程序运行效果图:


这里写图片描述


OK!经过本篇文章的学习,相信大家对Android对话框的使用已经非常熟练了。那么本篇文章到这也就结束了,谢谢大家观看~~~

2楼shuxiangtiankong5小时前
讲解的很细致,不错~~~
1楼a8461762845小时前
看了大神的解说,有一种醍醐灌顶的感觉,有好几个不明白的问题瞬间就解决了!
  相关解决方案