Android:修改AlertDialog的背景并動(dòng)態(tài)控制AlertDialog的最大高度

一、為什么要修改AlertDialog的背景并動(dòng)態(tài)控制其最大高度呢?

關(guān)于為啥要修改背景并控制其最大高度,其實(shí)只看下面這一張圖就夠了。

image.png

在上面的圖中,我們可以看出,AlertDialog 中內(nèi)容的默認(rèn)背景是一張白底的具有大約 8px 圓角的背景圖。然后我們查看 Theme.Holo.Light.Dialog中的windowBackground定義,發(fā)現(xiàn)該背景圖其實(shí)是一張名為 dialog_full_holo_light .9的圖

如果你想要一個(gè)圓角更大一點(diǎn)的圓角,那么你的直覺(jué)可能會(huì)告訴你去使用 AlertDialog.Builder 中的setView ( view ) , 在 view 中控制 背景為你需要的圓角圖,但是,非常抱歉,這樣行不通——如果你定義的圓角弧度大于 默認(rèn) .9 圖的弧度,那么,你就能看到四個(gè)角上的 白色小角;而且,如果你調(diào)用了setMessage 之類的AlertDialog的原有控件,那么,這些控件的背景色也是沒(méi)有變化的。也就是說(shuō),你設(shè)置的只是 view 的背景,而不是 AlertDialog 的背景。效果如下:

image.png

那么,為啥要控制 AlertDialog的最大高度呢?這個(gè)很明顯,像上面這兩個(gè)AlertDialog 實(shí)在是太不美麗了,而且超出屏幕的內(nèi)容也無(wú)法再展示出來(lái)。我們希望的是,當(dāng)內(nèi)容過(guò)多時(shí),讓他滾動(dòng)展示;當(dāng)內(nèi)容較少時(shí)有多少展示多少。

二、需求實(shí)現(xiàn)

不分析了, 都在下面的代碼里了,注釋的很明了。哪些方法好用,哪些方法不好用也都注釋了。

修改背景的方式呢,網(wǎng)上有說(shuō)修改 style 樣式 的,但是實(shí)際使用之后沒(méi)有達(dá)到預(yù)期效果,style 的代碼如下:

  <style name="DialogIOS" parent="@android:style/Theme.Holo.Light.Dialog">
        <item name="layout">@layout/custom_alertdialog</item>
        <item name="android:windowBackground">@drawable/shape_bk_cnoneralert</item>
    </style>

然后在創(chuàng)建dialog的時(shí)候指定 style , 代碼在下面完整代碼中有體現(xiàn),但是不好使啊。

關(guān)于控制最大高度的,網(wǎng)上很多的實(shí)現(xiàn)其實(shí)都是固定死了最大高度,如果內(nèi)容過(guò)大的時(shí)候顯示正常,但是如果內(nèi)容達(dá)不到最大值,那么很抱歉,底下會(huì)有一堆空白區(qū)域,參考下面的效果圖。關(guān)于這種情況的示例代碼,在下面也有列出。

底部有一塊無(wú)內(nèi)容的區(qū)域

三、 完整代碼

最終效果示意圖:

內(nèi)容未達(dá)到最大高度時(shí)的效果
內(nèi)容超過(guò)最大高度時(shí)的效果
/**
 * 作者:CnPeng
 * <p>
 * 時(shí)間:2017/6/28:上午10:02
 * <p>
 * 說(shuō)明:實(shí)現(xiàn)的最終效果:
 * 1 、修改AlertDialog的那個(gè)默認(rèn)的圓角很小的背景。
 * -- 使用 dialog.getWindow().setLayoutBackgroundResource()或 setBackgroundDrawable()
 * 2 、限制AlertDialog 的最大高度,未超過(guò)最大高度時(shí)內(nèi)容多高就多高,超過(guò)最大高度時(shí)以最大高度為準(zhǔn)
 * -- 使用 addOnLayoutChangeListener() 或 ViewTreeObserver
 * <p>
 * 要點(diǎn):
 * 1 、展示dialog 的時(shí)候必須調(diào)用 AlertDialog 對(duì)象的show()
 * 2 、addOnLayoutChangeListener 的時(shí)候 在 show 之前或者 show 之后都可以
 * 3 、addOnLayoutChangeListener 中重新setLayoutParams 的時(shí)候必須是 FrameLayout.LayoutParams
 * 4 、ViewTreeObserver 方式需要在 show 之前調(diào)用
 */

public class CornerAlertDialogActivity extends AppCompatActivity {

    private Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_conor_alertdialog);

        context = this;

        Button button = (Button) findViewById(R.id.bt_showCornorAlertDialog);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showCornerAlertDialog();
            }
        });
    }

    private void showCornerAlertDialog() {
        //設(shè)置圓角背景的方式 1 :
        //Dialog dialog = new Dialog(this);
        //Window window = dialog.getWindow();
        //window.setBackgroundDrawableResource(R.drawable.shape_bk_cnoneralert);
        //ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 
        //        ViewGroup.LayoutParams.MATCH_PARENT);
        //View view = LayoutInflater.from(this).inflate(R.layout.custom_alertdialog, null);
        //dialog.setContentView(view, layoutParams);
        //dialog.show();


        // 使用style模式設(shè)置的windowBackground 并不好使,依舊會(huì)有默認(rèn)背景的展示
        //AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.DialogIOS); 

        //完整設(shè)置圓角和最大高度 方式1 :
        // 還要注意:如果使用builder 去 setView,那么獲取alertDialog對(duì)象的操作必須在setView完畢之后,否則,界面中只有一個(gè)背景,不顯示內(nèi)容。
        //或者,直接先獲取AlertDialog對(duì)象,然后用alertDialog 本身的setView 去設(shè)置View.
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        final View view = LayoutInflater.from(this).inflate(R.layout.custom_alertdialog, null);
        builder.setMessage("TestMessage xxxxxxx");
        builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.setView(view);  //在setView之前調(diào)用builder的原有設(shè)置控件方法時(shí),能展示設(shè)置的控件,之后設(shè)置的則不展示??!
        AlertDialog dialog = builder.create();
        dialog.getWindow().setBackgroundDrawable(getResources().getDrawable(R.drawable.shape_bk_cnoneralert));
        //builder.show();   //用這個(gè)的話,背景并不會(huì)改變,依舊是默認(rèn)的

        dialog.show();  //必須用這個(gè)show 才能顯示自定義的dialog window 的背景

        //這種設(shè)置寬高的方式也是好使的!??!-- show 前調(diào)用,show 后調(diào)用都可以?。?!
        view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                                       int oldRight, int oldBottom) {
                int height = v.getHeight();     //此處的view 和v 其實(shí)是同一個(gè)控件
                int contentHeight = view.getHeight();

                LogUtils.e("高度", height + " / " + " / " + contentHeight);
                int needHeight = 500;

                if (contentHeight > needHeight) {
                    //注意:這里的 LayoutParams 必須是 FrameLayout的?。?                    view.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, 
                            needHeight));
                }
            }
        });


        //==============================================================================================================
        //// 完整設(shè)置圓角和最大高度 方式2: 修改AlertDialog的背景,同時(shí)控制最大的高度,超過(guò)了則展示到最大高度,沒(méi)超過(guò)則有多少展示多少
        //AlertDialog.Builder builder = new AlertDialog.Builder(context);
        //builder.setCancelable(false);                   //這個(gè)true和false表示點(diǎn)擊返回鍵時(shí)能否關(guān)閉dialog
        //
        //final View updateDialogView = LayoutInflater.from(context).inflate(R.layout.custom_alertdialog, null);
        //// 使用style模式設(shè)置的windowBackground 并不好使,依舊會(huì)有默認(rèn)背景的展示
        ////        builder.setView(updateDialogView); 
        //AlertDialog alertDialog = builder.create();
        //alertDialog.setCanceledOnTouchOutside(false);   //點(diǎn)擊dialog外部的區(qū)域不予許關(guān)閉
        //alertDialog.setView(updateDialogView);
        //
        //final Window window = alertDialog.getWindow();
        //if (null != window) {
        //    window.setBackgroundDrawableResource(R.drawable.shape_bk_cnoneralert);//更改dialog默認(rèn)背景
        //
        //    ViewTreeObserver vto = updateDialogView.getViewTreeObserver();
        //    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        //        public boolean onPreDraw() {
        //            int height = updateDialogView.getMeasuredHeight();  //獲取要繪制的高度
        //            int width = updateDialogView.getMeasuredWidth();
        //
        //            WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        //            DisplayMetrics metrics = new DisplayMetrics();  //獲取整個(gè)窗體的寬高
        //            wm.getDefaultDisplay().getMetrics(metrics);
        //            int windowHeight = metrics.heightPixels;
        //            int windowWidth = metrics.widthPixels;
        //
        //            int maxHeight = (int) (windowHeight * 0.577); //設(shè)計(jì)需求是770px ,但是770px顯示的內(nèi)容太少了
        //            int finalWidth = (int) (windowWidth * 0.733);
        //
        //            LogUtils.e("寬、高", height + "/" + width);
        //            if (height < maxHeight) {       //控制最大寬高
        //                window.setLayout(finalWidth, height);
        //            } else {
        //                window.setLayout(finalWidth, maxHeight);
        //            }
        //            return true;
        //        }
        //    });
        //}
        //alertDialog.show();     //必須用AlertDialog 對(duì)象去show

        //==============================================================================================================
        //這一個(gè)也是不好使的,不論是在show 前還是后, lp.width 拿到的值一直是 -2 
        // WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
        // lp.copyFrom(dialog.getWindow().getAttributes());
        // int dialogWidth = lp.width;
        // int dialogHeight = lp.height;
        //
        // if (dialogHeight > 700) {
        //     dialog.getWindow().setLayout(dialogWidth, 700);
        // }

        //==============================================================================================================
        // //這是設(shè)置圓角dialog的另外一個(gè)示例      
        // AlertDialog.Builder builder = new AlertDialog.Builder(this);
        //  View contentView = getLayoutInflater().inflate(R.layout.custom_alertdialog, null);
        //  builder.setView(contentView);
        //  AlertDialog dialog = builder.create();
        //  //        dialog.getWindow().setBackgroundDrawable(new BitmapDrawable()); // 背景透明.       
        //  dialog.getWindow().setBackgroundDrawable(getResources().getDrawable(R.drawable.shape_bk_cnoneralert));
        //  dialog.setCanceledOnTouchOutside(false); // 點(diǎn)擊外部不消失.       
        //  dialog.getWindow().setGravity(Gravity.CENTER); // 位置.      
        //  dialog.show();

        //==============================================================================================================
        //  //這種方法實(shí)際測(cè)試也是不好使??!getAttributes()獲取到的p中,p.height和 p.width 都是-2 ,如果想固定dialog的寬高的話,可以使用這種
        //  WindowManager m = getWindowManager();
        //  Display d = m.getDefaultDisplay(); // 獲取屏幕寬、高用       
        //  WindowManager.LayoutParams p = dialog.getWindow().getAttributes(); // 獲取對(duì)話框當(dāng)前的參數(shù)值      
        //  p.height = (int) (d.getHeight() * 0.4); // 高度設(shè)置為屏幕的0.4      
        //  p.width = (int) (d.getWidth() * 0.9); // 寬度設(shè)置為屏幕的0.9  
        // dialog.getWindow().setAttributes(p);//  注意: dialog.getWindow().setAttributes(p); 須在 show() 方法之后調(diào)用

        //==============================================================================================================
        ////下面這種方式實(shí)際測(cè)試并不好使!!heightPixels 一直就是屏幕整體的高度,而不是dialog內(nèi)容區(qū)域的高度!??!
        // 如果想直接固定大小的話可以使用該方法,需要在show 之后調(diào)用
        // //WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        // WindowManager wm = getWindowManager();
        // DisplayMetrics metrics = new DisplayMetrics();
        // wm.getDefaultDisplay().getMetrics(metrics);
        // if (metrics.heightPixels < 200) {
        //     dialog.getWindow().setLayout(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams
        //             .WRAP_CONTENT);
        // } else {
        //     dialog.getWindow().setLayout(WindowManager.LayoutParams.WRAP_CONTENT, 100);
        // }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,001評(píng)論 25 709
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程,因...
    小菜c閱讀 7,322評(píng)論 0 17
  • 第二天的行程主要是班提色瑪寺、女王宮和吳哥窟。 到班提色瑪寺的時(shí)候是臨近中午了,陽(yáng)光很強(qiáng),陰影很濃。每一扇窗、每一...
    熊布晨閱讀 395評(píng)論 0 2
  • 讀了朱曉平的微教育,收獲頗豐!現(xiàn)梳理如下: 改變的觀念: 1.靜心才能清醒教育 2教育是個(gè)人修行,不斷覺(jué)察自己,使...
    悠悠茶香遠(yuǎn)閱讀 3,211評(píng)論 0 5
  • 在過(guò)每一天的時(shí)候。每天上班的時(shí)候,其實(shí)有一個(gè)好心情是很重要的。有些時(shí)候心情會(huì)莫名的低落,無(wú)緣無(wú)故的,可能是某件事,...
    樂(lè)無(wú)彩閱讀 830評(píng)論 0 0

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