全屏到任意宽高的Dialog的写法

简介

本篇博客主要是介绍如何实现全屏Dialog,以及部分原理,具体细节可以参考对应Dialog的源码实现。


基础知识

前提

讲解前你需要具备如何去写一个Dialog的基础知识,因为本篇博客不会很细节的讲解此处内容,此博客会着重讲解如何实现一个全屏的Dialog,当然有关此篇博客中探讨出现的问题或者其他的疑问欢迎留言提问 ~。


实现方式

通过设置Style实现Dialog全屏

此方法比较简单的就可以实现全屏的Dialog,我们看下如何实现呢。

首先需要在res/values/styles.xml内写入如下代码即可:

 <!--此处的名字可以任意写,只要使用的时候匹配到即可-->
 <style name="dialog_style_1">
         <!--注意此处的属性,设置此属性后即可实现Dilaog全屏-->
        <item name="android:windowFullscreen">true</item>
    </style>

是不是很简单,如上方声明好一个Style后,怎么使用呢?

// 方式1,直接继承Dialog的时候传入Style即可
public class Dialog1 extends Dialog {
    public Dialog1(@NonNull Context context) {
        //注意此处
        super(context, R.style.dialog_style_1);
        setContentView(R.layout.dialog_test_layout);
    }
}

//------------------
//方式2
Dialog dialog=new Dialog(context,R.style.dialog_style_1);

上面两种实现的效果一致,是不是很简单呢?

来个效果图瞅瞅效果吧,效果图如下:
通过Theme设置全屏Dialog

总结:此类使用theme 的方式去设置全屏,设置windowFullscreen属性为true 即可

  • 优点:简单,全屏
  • 缺点:会导致整个屏幕被遮盖,包括状态栏,且点击状态栏会导致状态栏再次显示(体验并不好),只适合全屏。

通过设置Style实现Dialog全屏2

看到上面的标题,你是不是怀疑我写错了,并没有,这个也是通过Style实现的不过设置的属性和上面的不同,达到的效果也不尽相同。

当然设置Style的方式和上面一样只需要换个属性就好了,按照如下设置:

<!--此属性设置的dialog可以依照布局的宽高去设定而不是wrap_content-->
    <style name="dialog_style_2">
        <!--注意此处-->
        <item name="android:windowIsFloating">false</item>
    </style>

当然使用方式也是一致的,按照如之前的使用方式,只需将R.style.dialog_style_1更改为R.style.dialog_style_2 即可。

看下效果图:
通过Theme设置全屏Dialog

总结:此方法通过设置themewindowIsFloating 为false ,从而使得contentViewmatch_parentwindow起作用,从而达到全屏的效果,否则会设置window的宽高为wrap_content,无法全屏,当然你可以通过设置一个空的Style,也可达到相同效果(windowIsFloating 默认为false),但不可以不设置Style,因为会有默认的Style。

  • 优点:简单,显示的window在状态栏下面
  • 缺点:粒度小,且window一直为match_parent 即使内容变小,window仍不变小 ,导致外部无法触发点击消失事件,适合显示在状态栏下全屏的dialog,只适合全屏

通过代码设置Dilaog全屏或者任意宽高

这个方法内就比较灵活了,你可以任意设置Dilaog的宽高,不过代码量也会变高,好吧,看下怎么实现。
上代码:

public class Dialog3 extends Dialog {


    public Dialog3(@NonNull Context context, float widthPercent, float heightPercent) {
        super(context);
        setContentView(R.layout.dialog_test_layout);
        // 注意此方法一定要在setContentView后面,否则设置内容会被setContentView覆盖,此时由于默认没使用theme,按照默认的背景图来设置
        // 此时再设置window的宽高进行更细致的修改window参数
        initWidthAndHeightByPercent(widthPercent, heightPercent);
    }

    /**
     * 用于根据传入的宽高的比例显示window
     */
    private void initWidthAndHeightByPercent(float widthPercent, float heightPercent) {
        WindowManager windowManager = getWindow().getWindowManager();
        Display display = windowManager.getDefaultDisplay();
        WindowManager.LayoutParams lp = getWindow().getAttributes();
        //decorView是window中的最顶层view,可以从window中获取到decorView,获取状态栏的高度
        int statusBarHeight = getStatusBarHeight();
        lp.width = (int) (display.getWidth() * widthPercent); //设置宽度
        //高度值需要减去状态栏的高度
        lp.height = (int) ((display.getHeight() - statusBarHeight) * heightPercent);
        getWindow().setAttributes(lp);
        // 注意此处必须设置,因为window默认会设置一个有padding 的背景
        getWindow().setBackgroundDrawable(new ColorDrawable(Color.WHITE));
    }

    private int getStatusBarHeight() {
        int statusBarHeight1 = -1;
        //获取status_bar_height资源的ID
        int resourceId = getContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            //根据资源ID获取响应的尺寸值
            statusBarHeight1 = getContext().getResources().getDimensionPixelSize(resourceId);
        }
        return statusBarHeight1;
    }
}

不要被上面的代码吓坏了,其实内容也不多,我来讲解下主要过程,首先需要注意的就是你设置window的宽高的代码一定要在setContentView之后,原因和方法2中提到的相关,其内部会将不设置android:windowIsFloating 属性的window按照wrap_content来测量,所以,即使你设置match_parent也是无效的,而我们如果通过代码手动修改宽高当然也就达到修改的目的,如果顺序修改,就会导致setContentView方法将其重置。

具体参考PhoneWindow的代码(节选):

 if (mIsFloating) {
     setLayout(WRAP_CONTENT, WRAP_CONTENT);
     setFlags(0, flagsToUpdate);
        } 

这个代码就是在setContentView内执行,很明显,由于你没设置Style,系统将会使用默认的Style从而导致mIsFloatingtrue,然后通过代码再次修改window的宽高即可达到修改的结果。

从上面那个比较长的代码我们也可以看出,Dialog的宽高是可以自己设定的,所以通过此方法可以设定Dialog的任意宽高。

效果同效果图2,在此不重复截图了。

总结: 使用代码设置宽高

  • 优点:粒度小,可以任意设置

  • 缺点:操作略微复杂


总结

至此你已经掌握了三种设置Dilaog全屏的方式和一种设置Dilaog任意宽高的方式,也知道了他们每个的优缺点,我将代码上传至 -> CSDN <- 中,写了个简单的工具,后续加入动画的话,可以实现各种大小各种位置的Dialog的显示,如有疑问,欢迎留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章