美文网首页Dialog安卓对话框
Android对话框(Dialog)完全使用手册

Android对话框(Dialog)完全使用手册

作者: 周总_ | 来源:发表于2017-03-02 23:26 被阅读2872次

    Dialog对话框是android常用的基础视图组件之一,本文总结了对话框常用的几种样式,以及自定义视图和带动画效果的对话框

    Dialog虽然可以显示到屏幕上,但是Dialog并非继承自View,而是继承自Object。Dialog的生命周期由Activity来控制,所以当Activity被销毁后,如果再有对Dialog的操作会导致异常:java.lang.IllegalArgumentException: View not attached to window manager。
    当Dialog显示的时候,下面的Activity会失去焦点,用户的注意力将全部集中在Dialog上,进行操作;当Dialog消失后,Activity将重新获得焦点。

    1 常用样式对话框

    1.1 双按钮对话框

    先上图

    双按钮对话框

    再上代码,最后解释

    final AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this) {
        @Override
        public AlertDialog create() {
            d("对话框create,创建时调用");
            return super.create();
        }
    
        @Override
        public AlertDialog show() {
            d("对话框show,显示时调用");
            return super.show();
        }
    };
    
    dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
        public void onCancel(DialogInterface dialog) {
            d("对话框取消");
        }
    });
    
    dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
        public void onDismiss(DialogInterface dialog) {
            d("对话框销毁");
        }
    });
    
    dialog.setIcon(R.mipmap.ic_launcher)
            .setTitle("我是标题")
            .setMessage("我是要显示的消息")
            .setCancelable(true)
            .setPositiveButton("确定",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            d("点击确定");
                        }
                    })
            .setNegativeButton("取消",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            d("点击取消");
                        }
                    });
    dialog.show();
    

    创建对话框采用了建造者模式,通过构建AlertDialog.Builder来进行参数设置,最后通过show函数显示对话框。
    初始化AlertDialog.Builder的时候,可以重写create和show函数,在创建和显示的时候做一些额外工作。

    setOnCancelListener:设置对话框取消时的回调函数
    setOnDismissListener:设置对话框消失时的回调函数
    setIcon:设置对话框的图标
    setTitle:设置对话框标题
    setMessage:设置对话框消息
    setCancelable:设置对话框是否可以被取消,如果是true,则点击非对话框区域,对话框消失;false则刚好相反
    setPositiveButton:设置确定按钮的文字和回调函数
    setNegativeButton:设置取消按钮的文字和回调函数
    show:显示对话框

    这里要注意一点,对话框的cancel和dismiss两个函数的区别
    查看源码可以发现

    public void cancel() {
        if (mCancelMessage != null) {
            // Obtain a new message so this dialog can be re-used
            Message.obtain(mCancelMessage).sendToTarget();
        }
        dismiss();
    }
    
    public void setOnCancelListener(final OnCancelListener listener) {
        if (listener != null) {
            mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener);
        } else {
            mCancelMessage = null;
        }
    }
    

    如果没有调用setOnCancelListener,那么cancel和dismiss两个函数功能是一样的;当调用了setOnCancelListener时,会在执行cancel函数时向观察者发出一个消息,仅此而已。

    1.2 三按钮对话框

    三按钮对话框
    final AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
    dialog.setIcon(R.mipmap.ic_launcher)
            .setTitle("我是标题")
            .setMessage("我是要显示的消息")
            .setPositiveButton("确定",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            d("确定");
                        }
                    })
            .setNeutralButton("说明",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            d("说明");
                        }
                    })
            .setNegativeButton("取消",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            d("取消");
                        }
                    });
    dialog.show();
    

    与双按钮对话框相比,三按钮对话框多了作为说明操作的按钮,当对话框的message无法显示全部内容是,通过第三个按钮将用户引导到新的界面,显示长篇幅说明文字。

    1.3 列表对话框

    列表对话框
    final String[] items = {"项目1", "项目2", "项目3", "项目4"};
    AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
    dialog.setTitle("我是标题")
            .setItems(items, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    d("选择: " + items[which]);
                }
            });
    dialog.show();
    

    列表对话框,用于显示一个列表并进行单选。
    这里主要通过setItems函数为对话框配置要显示的列表和选择时的回调函数,选择后对话框自动消失。
    请注意回调函数的参数which从0开始。

    1.4 单选对话框

    单选对话框
    int select = 1; //表示单选对话框初始时选中哪一项
        
    final String[] items = {"项目1", "项目2", "项目3", "项目4"};
    AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
    dialog.setTitle("我是标题")
            .setSingleChoiceItems(items, select,
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            select = which;
                            d("选择: " + items[select]);
                        }
                    })
            .setPositiveButton("确定",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (select != -1) {
                                d("确定: " + items[select]);
                            }
                        }
                    });
    dialog.show();
    

    单选对话框,与列表对话框功能相似,主要区别是选择后对话框是否消失。单选对话框可以反复选择,直到用户点击确定按钮。
    setSingleChoiceItems函数的第一个参数是要显示的列表文本,第二个参数表示默认选中哪一项,下标从0开始。

    1.5 多选对话框

    多选对话框
    private ArrayList<Integer> list = new ArrayList<>();
    
    final String[] items = {"项目1", "项目2", "项目3", "项目4"};
    final boolean selected[] = {false, true, false, false};
    list.clear();
    for (int i = 0, size = selected.length; i < size; ++i) {
        if (selected[i]) {
            list.add(i);
        }
    }
    AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
    dialog.setTitle("我是标题")
            .setMultiChoiceItems(items, selected,
                    new DialogInterface.OnMultiChoiceClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                            if (isChecked) {
                                list.add(which);
                            } else {
                                list.remove(Integer.valueOf(which));
                            }
                        }
                    })
            .setPositiveButton("确定",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (list.size() == 0) {
                                d("你什么都没选啊,小伙");
                            } else {
                                StringBuilder str = new StringBuilder();
                                for (int i = 0, size = list.size(); i < size; i++) {
                                    str.append(items[list.get(i)]);
                                    if (i < size - 1) {
                                        str.append(", ");
                                    }
                                }
                                d("你选中了: " + str.toString());
                            }
                        }
                    });
    dialog.show();
    

    setMultiChoiceItems函数
    参数1:设置要显示的文本列表items
    参数2:和文本数据个数一致的boolean数组selected,selected[i]表示items[i]是否是选中状态
    参数3:选项被点击时的回调函数,isChecked为true表示选中;false表示取消

    1.6 等待对话框

    等待对话框
    ProgressDialog dialog = new ProgressDialog(MainActivity.this);
    dialog.setTitle("我是标题");
    dialog.setMessage("等待中...  想关闭请杀掉app");
    dialog.setIndeterminate(true);
    dialog.setCancelable(false);
    dialog.show();
    

    这里使用了ProgressDialog,由于setCancelable设置为false,对话框无法取消,所以此时只能杀死app!
    setIndeterminate参数为true表示该进度条不能明确等待进度,仅仅告知用户需要等待,没有预期。

    1.7 进度对话框

    进度对话框
    int progress = 0;
    
    final int MAX_PROGRESS = 100;
    final ProgressDialog dialog = new ProgressDialog(MainActivity.this);
    dialog.setTitle("我是标题");
    dialog.setProgress(0);
    dialog.setMax(MAX_PROGRESS);
    dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
        public void onCancel(DialogInterface dialog) {
            mHandler.removeCallbacksAndMessages(null);
            d("进度被打断");
        }
    });
    dialog.show();
    
    progress = 0;
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            d("" + progress);
            progress++;
            dialog.setProgress(progress);
            if (progress == 100) {
                dialog.cancel();
            } else {
                mHandler.postDelayed(this, 100);
            }
        }
    }, 100);
    

    同样使用ProgressDialog表示一个有进度概念的等待对话框,给用户一个心理预期。
    setProgress函数:设置当前进度值
    setMax函数:设置最大进度值
    setProgressStyle函数:设置进度条类型

    1.8 日期选择对话框

    日期选择对话框
    Calendar c = Calendar.getInstance();
    DatePickerDialog dialog = new  DatePickerDialog(MainActivity.this,
            new DatePickerDialog.OnDateSetListener() {
                @Override
                public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                    d("选择日期:" + year + "年" + (monthOfYear+1) + "月" + dayOfMonth + "日");
                }
            }, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
    dialog.show();
    

    注意,当选择成功回调的时候,月份是从0开始的,所以要注意加一。

    1.9 时间选择对话框

    时间选择对话框
    Calendar c = Calendar.getInstance();
    TimePickerDialog dialog = new TimePickerDialog(MainActivity.this,
            new TimePickerDialog.OnTimeSetListener() {
                @Override
                public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                    d("选择时间:" + hourOfDay + "时" + minute + "分");
                }
            }, c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), true);
    dialog.show();
    

    构造参数最后一个参数true表示采用24小时制

    2 自定义对话框

    2.1 自定义UI对话框

    自定义UI对话框
    public class CustomDialog1 extends Dialog {
    
        private Context context;
    
        public CustomDialog1(Context context) {
            super(context);
            init(context);
        }
    
        private void init(Context context) {
            this.context = context;
            build();
        }
    
        private void build() {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = inflater.inflate(R.layout.custom_dialog1_layout, null);
    
            view.findViewById(R.id.like).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(context, "喜欢", Toast.LENGTH_SHORT).show();
                    dismiss();
                }
            });
    
            view.findViewById(R.id.dislike).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(context, "一般", Toast.LENGTH_SHORT).show();
                    dismiss();
                }
            });
    
            setContentView(view);
        }
    }
    

    先通过inflate函数解析布局文件,然后通过setContentView为对话框设置视图

    2.2 自定义尺寸位置对话框

    自定义尺寸位置对话框
    public class CustomDialog2 extends Dialog {
    
        private Context context;
    
        public CustomDialog2(Context context) {
            super(context);
    //        super(context, R.style.custom_dialog2_style);
            init(context);
        }
    
        public void init(Context context) {
            this.context = context;
            setContentView(R.layout.custom_dialog2_layout);
    
            Window window = getWindow();
            window.setBackgroundDrawableResource(R.drawable.custom_dialog1_bg);//设置window的背景色
            WindowManager.LayoutParams lp = window.getAttributes();
            window.setGravity(Gravity.BOTTOM);
    
            lp.x = 250;
            lp.y = 250;
            lp.width = 400;
            lp.height = 400;
            lp.alpha = 0.8f;
            window.setAttributes(lp);
    
            setCanceledOnTouchOutside(true);//设置点击Dialog外部任意区域关闭Dialog
        }
    }
    

    custom_dialog2_layout布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="@android:color/holo_red_dark"
        >
    
    </FrameLayout>
    

    对话框的gravity是通过window的setGravity来实现贴边功能的。

    对话框窗口大小是通过WindowManager.LayoutParams来进行调整的:
    x:负数表示向左移动,正数表示向右移动
    y:负数表示向下移动,正数表示向上移动
    width:表示对话框的宽
    height:表示对话框的高
    alpha:表示对话框的透明度

    上面显示了这样一个对话框:
    1.对话框尺寸400400
    2.对话框居中贴底边
    3.右移250,上移250
    4.内部有一个80dp
    80dp的红色视图

    2.3 动画对话框

    动画对话框
    public class AnimDialog1 extends Dialog {
    
        private Context context;
    
        public AnimDialog1(Context context) {
            super(context);
            init(context);
        }
    
        private void init(Context context) {
            this.context = context;
            build();
        }
    
        private void build() {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = inflater.inflate(R.layout.custom_dialog1_layout, null);
    
            view.findViewById(R.id.like).setVisibility(View.GONE);
            view.findViewById(R.id.dislike).setVisibility(View.GONE);
    
            setContentView(view);
    
            Window window = getWindow();
            window.setWindowAnimations(R.style.dialog1_window_anim);
        }
    }
    

    对话框的出现消失动画是通过window的setWindowAnimations函数来设置的,这里并不是设置一个anim,而是设置了一个

    <style name="dialog1_window_anim" parent="android:Animation" >
        <item name="android:windowEnterAnimation">@anim/dialog1_enter_anim</item>
        <item name="android:windowExitAnimation">@anim/dialog1_exit_anim</item>
    </style>
    

    这里可以清楚的看到,可以为window设置进入和退出动画

    部分手机如果没有动画效果,请在Manifest.xml的application下的android:theme的style定义当中加入 <item name="android:windowNoTitle">true</item>

    3 其他

    3.1 对话框常用样式

    <item name="android:windowFrame">@null</item><!--是否有边框-->
    <item name="android:windowIsFloating">true</item><!--是否浮现在activity之上-->
    <item name="android:windowIsTranslucent">false</item><!--是佛半透明-->
    <item name="android:windowNoTitle">true</item><!--有无标题-->
    <item name="android:windowBackground">@android:color/holo_green_light</item><!--背景颜色-->
    <item name="android:backgroundDimEnabled">false</item><!--是否充许对话框的背景变暗-->

    相关文章

      网友评论

        本文标题:Android对话框(Dialog)完全使用手册

        本文链接:https://www.haomeiwen.com/subject/xcmfgttx.html