简介
本篇博客主要是介绍如何实现全屏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
的方式去设置全屏,设置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
的windowIsFloating
为false ,从而使得contentView
的match_parent
对window
起作用,从而达到全屏的效果,否则会设置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
从而导致mIsFloating
为true
,然后通过代码再次修改window
的宽高即可达到修改的结果。
从上面那个比较长的代码我们也可以看出,Dialog
的宽高是可以自己设定的,所以通过此方法可以设定Dialog
的任意宽高。
效果同效果图2,在此不重复截图了。
总结: 使用代码设置宽高
优点:粒度小,可以任意设置
缺点:操作略微复杂
总结
至此你已经掌握了三种设置Dilaog
全屏的方式和一种设置Dilaog
任意宽高的方式,也知道了他们每个的优缺点,我将代码上传至 -> CSDN <- 中,写了个简单的工具,后续加入动画的话,可以实现各种大小各种位置的Dialog的显示,如有疑问,欢迎留言。