AlertDialog入門與詳解(多種實(shí)現(xiàn)示例:自定義布局等)

廢話時(shí)間###

有一段時(shí)間沒好好敲代碼了,處理完手頭上一些瑣事,終于可以潛心修行,就從這篇簡單而飽滿的技術(shù)文章開始我的簡書之旅吧。
最近在不同項(xiàng)目做了一些不同的對話框,剛好來總結(jié)一下。方便自己,幫助他人。
本文由作者三汪首發(fā)于簡書。

總覽###

1.什么是AlertDialog
2.AlertDialog入門以及基本使用(快速創(chuàng)建Dialog)
3.AlertDialog的進(jìn)階(自定義布局、位置、大小、動(dòng)畫、style)

1.什么是AlertDialog###

Google官方的開發(fā)文檔是這樣描述的:

A subclass of Dialog that can display one, two or three buttons. If you only want to display a String in this dialog box, use the setMessage() method. If you want to display a more complex view, look up the FrameLayout called "custom" and add your view to it:
FrameLayout fl = (FrameLayout) findViewById(android.R.id.custom); fl.addView(myView, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
The AlertDialog class takes care of automatically setting WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM for you based on whether any views in the dialog return true from View.onCheckIsTextEditor(). Generally you want this set for a Dialog without text editors, so that it will be placed on top of the current input method UI. You can modify this behavior by forcing the flag to your desired mode after calling onCreate(Bundle).

翻譯如下(手動(dòng)翻譯的,可能不夠信達(dá)雅):

AlertDialog是Dialog的一個(gè)子類,可以顯示一到三個(gè)button。如果你只想在對話框中顯示一個(gè)字符串,使用serMessage()這個(gè)方法。如果你想要顯示更復(fù)雜的視圖,找到這個(gè)叫"custom"的幀布局并把你的視圖添加進(jìn)去:
FrameLayout fl = (FrameLayout) findViewById(android.R.id.custom); fl.addView(myView, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
AlertDialog這個(gè)類根據(jù)是否有視圖從View.onCheckIsTextEditor()返回true來為你自動(dòng)設(shè)置WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM通常你會(huì)想要為一個(gè)沒有文本編輯欄的對話框設(shè)置這個(gè)屬性,以便于該對話框被放置在當(dāng)前輸入法界面的頂部。你可以在調(diào)用onCreate(Bundle)以后通過設(shè)置這個(gè)flag修改這一動(dòng)作。

從官方文檔的描述中我們可以知道AlertDialog的這么幾個(gè)信息:

  • 直接繼承自Dialog
  • 可以有三個(gè)原生的button
  • 可以顯示文字也可以在原生的FrameLayout布局中添加自定義視圖

官方文檔沒有告訴我們的是:

  • 自定義布局可以不使用官方提供的FrameLayout
  • 可以自定義對話框出現(xiàn)和消失時(shí)的動(dòng)畫
  • 可以設(shè)置對話框的大小、位置和style

下面我們來逐一說明。

2.快速創(chuàng)建你的Dialog###

代碼如下(可直接copy進(jìn)你的項(xiàng)目使用):

        AlertDialog dialog = new AlertDialog.Builder(this).create();//創(chuàng)建對話框
        dialog.setIcon(R.mipmap.ic_launcher);//設(shè)置對話框icon
        dialog.setTitle("這是一個(gè)AlertDialog");//設(shè)置對話框標(biāo)題
        dialog.setMessage("Hello world");//設(shè)置文字顯示內(nèi)容
        //分別設(shè)置三個(gè)button
        dialog.setButton(DialogInterface.BUTTON_POSITIVE,"確定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();//關(guān)閉對話框
            }
        });
        dialog.setButton(DialogInterface.BUTTON_NEUTRAL,"點(diǎn)我試試", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) { }
        });
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();//關(guān)閉對話框
            }
        });
        dialog.show();//顯示對話框

效果圖


基礎(chǔ)對話框效果圖

Tips

  • AlertDialog的三個(gè)button對應(yīng)DialogInterface中的三個(gè)常量,分別是:BUTTON_NEUTRAL,BUTTON_POSITIVE,BUTTON_NEGATIVE。不同的常量所對應(yīng)的button位置不同。其中,BUTTON_NEUTRAL在對話框左側(cè),另外兩個(gè)在右側(cè)(不同版本的系統(tǒng)可能對應(yīng)的位置不同,以實(shí)際情況為準(zhǔn))。
  • AlertDialog dialog = new AlertDialog.Builder(this).create();的Builder()中傳入的context參數(shù)必須來自activity,而不能是application的,否則會(huì)報(bào)錯(cuò)。
  • 當(dāng)你什么都不設(shè)置的時(shí)候,會(huì)彈出一個(gè)“白茫茫大地真干凈”的對話框。
  • 調(diào)用dismiss()方法可以關(guān)閉對話框。除了在button點(diǎn)擊事件中,還可以用在CheckBox、RadioButton的onCheckedChanged事件中等,以實(shí)現(xiàn)在用戶完成選擇以后自動(dòng)關(guān)閉對話框的功能。
  • setTitle、setMessage、setPositiveButton等這類設(shè)置動(dòng)作還可以用builder對象來做,寫法不同,效果一樣。此處不再贅述。

3.簡單列表、單選列表與復(fù)選列表對話框的實(shí)現(xiàn)示例###

簡單列表代碼如下:

        //初始化字符串?dāng)?shù)組
        final String[] strArray = new String[]{"床前明月光","意識地上霜","舉頭望明月","低頭思故鄉(xiāng)"};
        AlertDialog.Builder builder = new AlertDialog.Builder(this);//實(shí)例化builder
        builder.setIcon(R.mipmap.ic_launcher);//設(shè)置圖標(biāo)
        builder.setTitle("簡單列表");//設(shè)置標(biāo)題
        //設(shè)置列表
        builder.setItems(strArray, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(MainActivity.this,strArray[which],Toast.LENGTH_SHORT).show();
            }
        });
        builder.create().show();//創(chuàng)建并顯示對話框

單選列表代碼如下:

        //初始化字符串?dāng)?shù)組
        final String[] strArray = new String[]{"離離原上草","一歲一枯榮","野火燒不盡","春風(fēng)吹又生"};
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);//實(shí)例化builder
        builder.setIcon(R.mipmap.ic_launcher);//設(shè)置圖標(biāo)
        builder.setTitle("單選列表");//設(shè)置標(biāo)題
        //設(shè)置單選列表
        builder.setSingleChoiceItems(strArray, 0, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        //創(chuàng)建對話框
        AlertDialog dialog = builder.create();

        //設(shè)置確定按鈕
        dialog.setButton(DialogInterface.BUTTON_POSITIVE,"確定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        dialog.show();//顯示對話框

復(fù)選列表代碼如下:

  //初始化字符串?dāng)?shù)組
        final String[] strArray = new String[]{"白日依山盡","黃河入海流","欲窮千里目","更上一層樓"};
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);//實(shí)例化builder
        builder.setIcon(R.mipmap.ic_launcher);//設(shè)置圖標(biāo)
        builder.setTitle("多選列表");//設(shè)置標(biāo)題
        //設(shè)置多選列表
        builder.setMultiChoiceItems(strArray, new boolean[]{false, false, false, false}, new DialogInterface.OnMultiChoiceClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which, boolean isChecked) {

            }
        });
        //創(chuàng)建對話框
        AlertDialog dialog = builder.create();
        //設(shè)置確定按鈕
        dialog.setButton(DialogInterface.BUTTON_POSITIVE,"確定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        dialog.show();//顯示對話框

效果圖:

簡單列表對話框效果圖
單選列表對話框效果圖
復(fù)選列表對話框效果圖

4.自定義布局對話框的簡單示例###

對于AlertDialog的自定義布局,官方提供了原生的FrameLayout(說明與使用方式參見前文開發(fā)文檔描述部分)供大家使用。但是,F(xiàn)rameLayout有時(shí)候并不能滿足大家的需求。因此,我們需要自己引入布局文件。本文僅提供如何通過引入布局文件來實(shí)現(xiàn)自定義布局的示例。

代碼如下:

        //實(shí)例化布局
        View view = LayoutInflater.from(this).inflate(R.layout.item_custom,null);
        //找到并對自定義布局中的控件進(jìn)行操作的示例
        EditText account = (EditText) view.findViewById(R.id.account);
        account.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });
        //創(chuàng)建對話框
        AlertDialog dialog = new AlertDialog.Builder(this).create();
        dialog.setIcon(R.mipmap.ic_launcher);//設(shè)置圖標(biāo)
        dialog.setTitle("自定義布局對話框");//設(shè)置標(biāo)題
        dialog.setView(view);//添加布局
        //設(shè)置按鍵
        dialog.setButton(AlertDialog.BUTTON_POSITIVE, "登陸", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        dialog.setButton(AlertDialog.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        dialog.show();

效果圖:


自定義布局對話框效果圖

5.如何設(shè)置Dialog的位置、大小、動(dòng)畫###

通過幾小段代碼來說明,以供參考。

代碼片段1:

        Window dialogWindow = dialog.getWindow();//獲取window對象
        dialogWindow.setGravity(Gravity.BOTTOM);//設(shè)置對話框位置
        dialogWindow.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);//設(shè)置橫向全屏
        dialogWindow.setWindowAnimations(R.style.share_animation);//設(shè)置動(dòng)畫

styles.xml

     <style name="share_animation" parent="android:Animation">
        <item name="@android:windowEnterAnimation">@anim/dialog_enter</item>  //進(jìn)入時(shí)的動(dòng)畫
        <item name="@android:windowExitAnimation">@anim/dialog_exit</item>    //退出時(shí)的動(dòng)畫
     </style>

dialog_enter.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    
    <translate
        android:fromYDelta="100%p"     <!--  %p指相對于父容器-->
        android:duration="600"                <!-- 持續(xù)時(shí)間-->
        />
</set>

dialog_exit.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    
    <translate
          android:toYDelta="100%p"
          android:duration="600"    
          />
</set>

代碼片段2:
(片段2與片段3轉(zhuǎn)載自:angeldevil)

        /*
         * 將對話框的大小按屏幕大小的百分比設(shè)置
         */
//        WindowManager m = getWindowManager();
//        Display d = m.getDefaultDisplay(); // 獲取屏幕寬、高用
//        WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 獲取對話框當(dāng)前的參數(shù)值
//        p.height = (int) (d.getHeight() * 0.6); // 高度設(shè)置為屏幕的0.6
//        p.width = (int) (d.getWidth() * 0.65); // 寬度設(shè)置為屏幕的0.65
//        dialogWindow.setAttributes(p);

代碼片段3:
(片段2與片段3轉(zhuǎn)載自:angeldevil)

        Window dialogWindow = dialog.getWindow();
        WindowManager.LayoutParams lp = dialogWindow.getAttributes();
        dialogWindow.setGravity(Gravity.LEFT | Gravity.TOP);

        /*
         * lp.x與lp.y表示相對于原始位置的偏移.
         * 當(dāng)參數(shù)值包含Gravity.LEFT時(shí),對話框出現(xiàn)在左邊,所以lp.x就表示相對左邊的偏移,負(fù)值忽略.
         * 當(dāng)參數(shù)值包含Gravity.RIGHT時(shí),對話框出現(xiàn)在右邊,所以lp.x就表示相對右邊的偏移,負(fù)值忽略.
         * 當(dāng)參數(shù)值包含Gravity.TOP時(shí),對話框出現(xiàn)在上邊,所以lp.y就表示相對上邊的偏移,負(fù)值忽略.
         * 當(dāng)參數(shù)值包含Gravity.BOTTOM時(shí),對話框出現(xiàn)在下邊,所以lp.y就表示相對下邊的偏移,負(fù)值忽略.
         * 當(dāng)參數(shù)值包含Gravity.CENTER_HORIZONTAL時(shí)
         * ,對話框水平居中,所以lp.x就表示在水平居中的位置移動(dòng)lp.x像素,正值向右移動(dòng),負(fù)值向左移動(dòng).
         * 當(dāng)參數(shù)值包含Gravity.CENTER_VERTICAL時(shí)
         * ,對話框垂直居中,所以lp.y就表示在垂直居中的位置移動(dòng)lp.y像素,正值向右移動(dòng),負(fù)值向左移動(dòng).
         * gravity的默認(rèn)值為Gravity.CENTER,即Gravity.CENTER_HORIZONTAL |
         * Gravity.CENTER_VERTICAL.
         * 
         * 本來setGravity的參數(shù)值為Gravity.LEFT | Gravity.TOP時(shí)對話框應(yīng)出現(xiàn)在程序的左上角,但在
         * 我手機(jī)上測試時(shí)發(fā)現(xiàn)距左邊與上邊都有一小段距離,而且垂直坐標(biāo)把程序標(biāo)題欄也計(jì)算在內(nèi)了,
         * Gravity.LEFT, Gravity.TOP, Gravity.BOTTOM與Gravity.RIGHT都是如此,據(jù)邊界有一小段距離
         */
        lp.x = 100; // 新位置X坐標(biāo)
        lp.y = 100; // 新位置Y坐標(biāo)
        lp.width = 300; // 寬度
        lp.height = 300; // 高度
        lp.alpha = 0.7f; // 透明度

        // 當(dāng)Window的Attributes改變時(shí)系統(tǒng)會(huì)調(diào)用此函數(shù),可以直接調(diào)用以應(yīng)用上面對窗口參數(shù)的更改,也可以用setAttributes
        // dialog.onWindowAttributesChanged(lp);
        dialogWindow.setAttributes(lp);

以上。
歡迎留言探討,指正。
希望我總結(jié)的東西能夠?qū)δ阌兴鶐椭?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 7,295評論 0 17
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,741評論 25 709
  • Day1: 在代碼中通過R.string.hello_world可以獲得該字符串的引用; 在XML中通過@stri...
    冰凝雪國閱讀 1,614評論 0 5
  • 不是優(yōu)種葡萄的老葡萄樹,葡萄架交錯(cuò)的藤蔓,竟然得早早為它準(zhǔn)備許多架桿。形成一個(gè)過廊。北方干燥的院子里,竟然生出一...
    咫尺為鄰閱讀 578評論 2 0
  • 2015年11月22日23:25:15 丁亥年,壬寅日,小雪至。 我一直特別喜歡這句話,一讀它,腦海里便會(huì)出現(xiàn)一些...
    邡素閱讀 450評論 0 0

友情鏈接更多精彩內(nèi)容