Dialog 是Android中对话框相关的类,起到相关提示的作用。
Dialog在Android 中主要分为以下几类:
AlertDialog :警告对话框(提示对话框)ProgressDialog:进度对话框DatePickerDialog:日期选择对话框TimerPickerDialog: 时间选择对话框下面将按照如上所分类,进行一一介绍。
AlertDialog 继承 Dialog,该对象对于常用的一些对话框进行了封装。
需要注意的是AlertDialog存在两种实现并对应的存在于两个不同的包,
android.app.AlertDialog。该包中的AlertDialog并没有对不同版本的系统进行适配。在不同的手机系统上会显示不同的样式。(不推荐)。android.support.v7.app.AlertDialog。该包中的AlertDialog是根据google 推出的Material Desgin进行设计的,并对低版本的系统进行了适配。支持系统版本到7(Android 2.1 )以上。(推荐)下面都将使用v7版本的AlertDialog
AlertDialog的使用分为以下几步:
AlertDialog.Builder对象,该对象能创建AlertDialog。Builder对象的方法设置图标、标题、内容、按钮等。 setTitle():为对话框设置标题setIcon ():设置图标setMessage ():设置要显示的信息setPositiveButton ():设置确定按钮setNegativeButton (): 设置取消按钮setNeutralButton ():设置中立按钮Builder对象的create()方法创建AlertDialog对话框。AlertDialog的show()方法来显示对话框AlertDialog的dimiss()方法销毁对话框。下面就根据上面的步骤,来创建AlertDialog方法。
    public void dialog1(View view){
        // 简单的AlertDialog
        // 1 . 创建AlertDialog 对象
        //          注意 Dialog 的Builder的创建虽然传入的是Context,其实是多态,此处必须传入Activity对象
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        // 2. 通过builder 设置一些常用的属性
        //   设置图标
        builder.setIcon(R.mipmap.ic_launcher);
        // 设置标题
        builder.setTitle("提示");
        //设置提示消息
        builder.setMessage("这是一个基础的AlertDialog");
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //点击确定按钮之后的回调
                Toast.makeText(AlertDialogActivity.this, "确定", Toast.LENGTH_SHORT).show();
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //点击取消按钮之后的回调
            }
        });
        builder.setNeutralButton("中间", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //点击中间的按钮的回调
            }
        });
        //3 .通过Builder  的 create方法创建AlertDialog;
        AlertDialog dialog = builder.create();
        // 4 . 显示对话框
        dialog.show();
    }
看一下效果
有以下几点需要注意:
AlertDialog和Builder导入的都是android.support.v7.app.AlertDialog。dimiss()方法,所以我们无需手动隐藏他。setPositiveButton和setNegativeButton。英文单词意为积极的和消极的。Dialog虽然需要的是Context,但必须传入Activity对象。如果观察仔细的会发现builder的sexXXX方法,返回的仍然是Builder对象。那么我们可以修改代码之后如下:
   AlertDialog dialog = new AlertDialog.Builder(this)
                .setIcon(R.mipmap.ic_launcher)
                .setTitle("提示")
                .setMessage("这是一个基础的AlertDialog")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //点击确定按钮之后的回调
                        Toast.makeText(AlertDialogActivity.this, "确定", Toast.LENGTH_SHORT).show();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //点击取消按钮之后的回调
                    }
                })
                .setNeutralButton("中间", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //点击中间的按钮的回调
                    }
                }).create();
类似一条链式的创建Dialog对象。
因为AlertDialog继承Dialog,所以他拥有Dialog的特性。(该特性对于所有的对话框都适用)
其中几个常用的方法:
setCancelable(boolean flag):当点击返回键的时候,Dialog是否消失。 true 表示点击返回键提示框消失。 false表示不消失,即点击返回无效果。setCanceledOnTouchOutside (boolean cancel) 点击对话框以外的区域时,对话框是否消失。true 表示点击以外的区域消失,false表示不消失。
        // 点击返回不会取消对话框
        dialog.setCancelable(false);
        // 触摸对话框以外的区域不会消失
        dialog.setCanceledOnTouchOutside(false);
注意:该方法是
Dialog的方法,不是Builder中的方法。
实现单选功能对话框有两种实现方式,通过两个方法setItems和setSingleChoiceItems。
setItems:通过该方法实现对话框,无需点击确定,直接点击条目之后立即消失,同时调用相应的回调。setSingleChoiceItems:普通的单选效果,带有圆圈,点击确定之后隐藏。首先看一下两个的效果图:
 
- setItems()方法实现单选
final String[] sex = {"男","女"};
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setItems(sex, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // which 表示的 点击的索引。
                        Toast.makeText(AlertDialogActivity.this, sex[which], Toast.LENGTH_SHORT).show();
                    }
                }).create();
        dialog.show();
setItems(CharSequence[] items, final OnClickListener listener): 第一个参数为显示不同数据的数组。第二个方法为选择之后的回调。
setSingleChoiceItems实现:
    public void choice_single(View view){
        final String[] sex = {"男","女"};
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setSingleChoiceItems(sex, 0,new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // which 表示的 点击的索引。
                        Toast.makeText(AlertDialogActivity.this, sex[which], Toast.LENGTH_SHORT).show();
                        //保存状态
                    }
                })
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 确定操作
                        //通过在上一个onClick方法中的回调的记录,进行对应操作。
                    }
                })
                .create();
        dialog.show();
    }
setSingleChoiceItems(CharSequence[] items, int checkedItem,final OnClickListener listener): 第一个参数表示数据数组,第二个参数表示默认选中第几条,第三个参数为借口回调。
setItems方式实现无法修改,只能选择一次,选中之后对话框就会消失。setSingleChoiceItems,可以设置默认的选中条目,多次选择,选中之后不会消失,直到点击确定等隐藏对话框的操作。AlertDialog.Builder中存在方法setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, DialogInterface.OnMultiChoiceClickListener listener)设置多选对话框。
CharSequence[] items:可选的条目的数组数据。boolean[] checkedItems:默认显示的状态,与条目一一对象,false表示不选中,true表示默认选中。DialogInterface.OnMultiChoiceClickListener listener:条目选择产生变化之后的回调看一下效果: 
具体代码
        final String[] like = {"足球","篮球","乒乓球","排球"};
        final boolean[] check = {false,false,true,true};
        AlertDialog dialog = new AlertDialog.Builder(this)
                .setMultiChoiceItems(like, check, new DialogInterface.OnMultiChoiceClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                        // which 数据变化的索引   isChecked 表示变化的结果
                        // 根据变化修改数据
                        check[which] = isChecked;
                    }
                })
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // 确定操作
                        //根据check 中的true 和 flase 进行处理不同结果。
                        String select = "";
                        for(int i = 0;i<check.length;i++){
                            if(check[i]){
                                select= select+","+like[i];
                            }
                        }
                        Toast.makeText(AlertDialogActivity.this, "选择了"+select, Toast.LENGTH_SHORT).show();
                    }
                })
                .create();
        dialog.show();setMultiChoiceItems中的OnMultiChoiceClickListener(),数据变化时回调此方法,我们需要在此方法中保存修改的数据。ProgressDialog 也是继承于Dialog,但其扩展了缓冲加载提示的功能。
总共分为两种样式,一种是圆形转圈的加载,一种是水平进度条(带有加载进度)的效果。
看一下效果:
看一下demo
  /**
     * 圆形加载对话框
     * @param view
     */
    public void progress_circle(View view){
        final ProgressDialog pd  = new ProgressDialog(this);
        // 进度条为水平旋转
        pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        // 设置点击返回不能取消
        pd.setCancelable(false);
        //设置触摸对话框以外的区域不会消失
        pd.setCanceledOnTouchOutside(false);
        // 设置提示的title的图标,默认是没有的,如果没有设置title的话只设置Icon是不会显示图标的
        pd.setIcon(R.mipmap.ic_launcher);
        // 设置标题
        pd.setTitle("提示");
        pd.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                // dimiss的监听
            }
        });
        pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                //cancel
            }
        });
        pd.setMessage("这是一个圆形进度条");
        pd.show();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    //pd.cancel();
                    pd.dismiss();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }new出ProgressDialog,并没有创建什么Builder类。setProgressStyle为ProgressDialog.STYLE_SPINNER,使其显示圆形加载效果。pd.dismiss()和pd.cancel()方法都能够隐藏加载对话框。 cancel()表示隐藏对话框,对话框并不会被销毁。会回调setOnCancelListener.dismiss():销毁对话框,回调setOnDismissListener。推荐使用
dismiss()方法。因为,如果调用了cancel,在activity结束时,仍要手动调用dismiss。不然,dialog如果没有销毁,则会导致内存溢出。
  /**
     * 水平加载进度对话框
     * @param view
     */
    public void progress_horizontal(View view){
        final ProgressDialog pd = new ProgressDialog(this);
        // 设置水平进度条
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        // 设置点击返回不能取消
        pd.setCancelable(false);
        //设置触摸对话框以外的区域不会消失
        pd.setCanceledOnTouchOutside(false);
        // 设置提示的title的图标,默认是没有的,如果没有设置title的话只设置Icon是不会显示图标的
        pd.setIcon(R.mipmap.ic_launcher);
        // 设置标题
        pd.setTitle("提示");
        // 默认为100
        pd.setMax(100);
        pd.setMessage("这是一个水平进度条");
        pd.show();
        new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while (i < 100) {
                    try {
                        Thread.sleep(200);
                        // 每次增加 1%
                        pd.incrementProgressBy(1);
                        i++;
                    } catch (Exception e) {
                    }
                }
                pd.dismiss();
            }
        }).start();
    }设置一个线程,通过线程没个200ms使进度值+1,最后销毁dialog。
setProgressStyle 为ProgressDialog.STYLE_HORIZONTALpd.setMax(),整形,默认为100。pd.incrementProgressBy(1);,改变当前进度值,传入的参数为递增量。Android 提供的原生控件,使用起来比较简单,但因为其没有对不同系统做适配,所以在不同系统上显示可能不同。只做了解即可。一般都是自定义日期对话框。
效果 
注意:该效果是在Android5.0和以上系统上显示的效果。具体适配会在后面提到。
使用方式
/**
     * 日期选择器
     * @param view
     */
    public void dialog_date(View view){
        // 年,天,时,分都是从 1 开始  月从1 开始
        // 获取系统当前时间
        Calendar instance = Calendar.getInstance();
        int year = instance.get(Calendar.YEAR);
        int month = instance.get(Calendar.MONTH); // 该方法month 从0 开始
        int day = instance.get(Calendar.DAY_OF_MONTH);
        // 构造dialog
        DatePickerDialog dialog = new DatePickerDialog(this,new DatePickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                // 获取到的month 需要+1 获取正确的月份
                Toast.makeText(AlertDialogActivity.this, year+"-"+monthOfYear+"-"+dayOfMonth, Toast.LENGTH_SHORT).show();
            }
        },year,month,day);
        dialog.show();
    }
通过Calendar获取系统当前时间,并通过DatePickerDialog的构造方法传入系统当前时间和相应的数据回调。最后在显示。
DatePickerDialog()构造方法有5个参数: 
- 当前Activity 
- onDateSetListener():数据的回调,在点击确定是将数据作为参数回调onDateSet方法。 
- year, 年 
- month,注意+1和-1 
- day,天
有以下几点注意:
Calendar还是DataPicker,他们的年,天,时,分都是从0开始的,也就是直接获取值显示即可。而月是从0开始的,即我们需要对数据进行+1或-1操作。 onDataSet回调的日期是2016,5,15。则在显示时需要对月份+1 ,即2016,6(5+1),15<colorAccent><!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <!-- 该字段设置dialog 的颜色-->
        <item name="colorAccent">@color/colorAccent</item>
    </style>
该控件的使用和DatePickerDialog的使用基本类似。
看一下效果 
注意:该效果是在Android5.0和以上系统上显示的效果。具体适配会在后面提到。
 /**
     * 时间选择器
     * @param view
     */
    public void dialog_time(View view){
        // 获取系统时间
        Calendar instance = Calendar.getInstance();
        int hour = instance.get(Calendar.HOUR_OF_DAY);
        int minute = instance.get(Calendar.MINUTE);
        // 时间对话框
        TimePickerDialog dialog = new TimePickerDialog(this, new TimePickerDialog.OnTimeSetListener() {
            @Override
            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                Toast.makeText(AlertDialogActivity.this, hourOfDay+"-"+minute, Toast.LENGTH_SHORT).show();
            }
        },hour,minute,true);
        //显示
        dialog.show();
    }
TimePickerDialog的有5个参数 
- 当前Activity的对象 
- onTimeSetListener,数据回调。 
- hour:小时 
- minute:分 
- is24hourView:  false:不使用24小时制。true:使用24小时表示。
在平常的项目中,因为系统提供的dialog无法很好的适配不同的版本(样式不同),通常自定义Dialog实现相应功能。
实现的步骤:
Dialog并实现构造方法。dialog的主题。setContentView设置到dialog中。看一下效果
dialog_simple.xml<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="@drawable/shape_dialog_psd_bg"
    android:layout_width="250dp"
    android:layout_height="400dp">
    <TextView
        android:layout_weight="1"
        android:gravity="center"
        android:text="一个简单的自定义dialog"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <LinearLayout
        android:layout_margin="10dp"
        android:layout_gravity="right"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/dialog_simple_cancel"
            android:textSize="16sp"
            android:textStyle="bold"
            android:text="关闭"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>
Dialog并没有提供对应的方法,我们需要从自定义布局上,设置它的背景为圆角矩形。圆角矩形shape资源shape_dialog_psd_bg.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="8dp" />
    <solid android:color="#fff" />
    <stroke
        android:width="1dp"
        android:color="#ececec" />
</shape>下面就是编写CustomDialog类
/**
 * 简单的对话框
 * Created by MH on 2016/6/15.
 */
public class SimpleDialog extends Dialog implements View.OnClickListener {
    public SimpleDialog(Context context) {
        // 注意,在此处设置样式
        super(context,R.style.CustomDialog);
        // 设置我们的布局到dialog中
        setContentView(R.layout.dialog_simple);
        // 初始化布局
        initView();
    }
    private void initView() {
        findViewById(R.id.dialog_simple_cancel).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.dialog_simple_cancel:
                // 对应的点击事件
                this.dismiss();
                break;
        }
    }
}在如上类中,关键的几步如下:
dialog的样式。setContentView()设置自定义布局到dialog中。其中需要注意的一点为设置样式,该样式设置的目的是为了统一不同系统版本下显示的样式,如果不设置,在低于Android5。0的系统下会爆炸。。。
在此定义的样式一般为
 <style name="CustomDialog" parent="@android:style/Theme.Dialog">
        <!-- 是否浮现在activity之上 -->
        <item name="android:windowIsFloating">true</item>
        <!-- 无标题 -->
        <item name="android:windowNoTitle">true</item>
        <!-- 背景透明 -->
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>自定义Dialog大概就这么多,复杂的无非就是界面复杂点,逻辑复杂点那么多。
看一下效果图
下面就开始实现,定义动画需要通过xml文件来编写动画
dialog_anim_enter.xml  进入的动画<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">
    <translate android:fromYDelta="-10%p" />
    <alpha
        android:fromAlpha="0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="1" />
</set>
dialog_anim_exit.xml 离开动画<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    >
    <translate android:toYDelta="60%p" />
    <alpha
        android:fromAlpha="1"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="0" />
</set>如果对动画不是太熟悉的,可以看我之前的博客Android动画之视图动画和属性动画
在这里需要注意,虽然是相对父布局,但仍然是我们显示的dialog的左上角为0坐标开始偏移的,效果是相对于本身的动画。我猜测应该是
dialog外层包裹了另一个和他一样大小的布局。
  <style name="DialogAnim" parent="@android:style/Animation">
        <item name="android:windowEnterAnimation">@anim/dialog_anim_enter</item>
        <item name="android:windowExitAnimation">@anim/dialog_anim_exit</item>
  </style>
dialog.getWindow().setWindowAnim(int resId)方法设置动画
/**
     * dialog设置动画
     */
    public void dialog_anim(View view){
        SimpleDialog dialog = new SimpleDialog(this);
        // 设置动画
        dialog.getWindow().setWindowAnimations(R.style.DialogAnim);
        dialog.show();
    }该动画的设置方法对所有的
dialog都适用,即之前系统提供的AlertDialog都适用。
两种实现方式:
第一种方式 通过dialog.getWindow().setLayout(100,100); 设置大小。
第二种方式 通过dialog.getWindow().getAttributes();设置。
    /**
     * 设置大小
     * @param view
     */
    public void dialog_size(View view) {
        SimpleDialog dialog = new SimpleDialog(this);
//        // 第一种方式
//        dialog.getWindow().setLayout(100,100);
        // 第二种方式  获取参数
        WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
        // 设置高度
        params.height = 100;
        // 设置宽度
        params.width = 100;
        // 设置
        dialog.getWindow().setAttributes(params);
        dialog.show();
    }params ,里面包含了很多dialog的显示属性,不是只要高度和宽度。该大小的设置方法对所有的
dialog都适用,即之前系统提供的AlertDialog都适用。
该博客中的源码已经更新到github,有需要者请移步。
原文:http://blog.csdn.net/lisdye2/article/details/51680135