前言
一个Activity持有一个PhoneWindow,PhoneWindow中就有我们今天的主角-DecorView,通过下图可以很明白的看到其地位。总的来说,DecorView就是我们设置的布局的最外层的布局,我们通过setContentView设置的布局只是DecorView的子布局而已。当然不同的手机以及不同的Android版本可能具体的层级不同,但是大致为这样。
DecorView是啥
DecorView只是一个普通的ViewGroup,继承自FrameLayout,既然他是一个ViewGroup那么我们可不可以在里面添加View呢?
final ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
decorView.post(new Runnable() {
@Override
public void run() {
View tv = LayoutInflater.from(MainActivity.this).inflate(R.layout.decor_layout, decorView, false);
decorView.addView(tv);
}
});
通过上面的代码可以看到我们添加的TextView已经添加到DecorView中了,并且由于DecorView是一个FrameLayout,我们的TextView在最顶层。
上面有一点需要注意的,我使用的是View.post()方法去延时添加View,这么做的原因是如果我们在onCreate中直接去添加View,可能后面的流程中系统会添加statusBar等,这样一来我们的视图就会被遮挡一部分。比如下面直接在onCreate中添加
@Override
protected void onCreate(Bundle savedInstanceState) {
ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
View tv = LayoutInflater.from(MainActivity.this).inflate(R.layout.decor_layout, decorView, false);
decorView.addView(tv);
}
可以看到,我们的视图被遮挡了一部分,因为系统后面又添加了一个statusBar,当然我们也可以在需要的使用使用View.bringToFront()/ViewGroup.bringChildToFront()去将添加的布局层级提升到最上面!
玩法一:程序闪屏页
一般的程序启动的时候都有一个闪屏页面,虽然我们能够通过自定义style的方式去添加一个闪屏页,但是如果当程序比较小,启动速度较快,那么闪屏页面的时间不容易控制,如果采用普通的方案,跳转到一个单独的Activity然后延时跳转到主界面,这样也不是不可以,但是总觉得不够优雅,当我们知道decorView可以添加布局以后我们能够想到什么呢!!!!直接跳转到主界面,然后添加闪屏界面到最上面,延迟销毁即可。
/**
* 加载闪屏页
*/
private void loadSplashView() {
final ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
final View view = LayoutInflater.from(this).inflate(R.layout.activity_splash_view, decorView, false);
//这里直接添加的原因是应为项目是全屏的,没有statusBar!!!
decorView.addView(view);
//延迟1.5s销毁
decorView.postDelayed(new Runnable() {
@Override
public void run() {
decorView.removeView(view);
}
},1500);
}
这样做的优点,如果我们没有使用ProgressDialog等去做加载等待的话,那么当我们的闪屏页显示出来的时候程序也能提前加载主页的数据,而且也稍微提升一点性能。# 玩法二:用户操作引导
类似于下图的效果,我们可以将一个View直接全屏添加在DecorView中,然后进行绘制,这样一来引导页面就完全脱离了具体的ui布局,实现了代码上面的解耦。具体可以参考
https://github.com/huburt-Hu/NewbieGuide
玩法三:使用View的Dialog
对于这种玩法只能说一句佩服,具体可以查看XPopup这个库,作者直接将布局添加到DecorView中,然后将其做各种动画,几乎以假乱真,首先添加进去的布局就是一个ViewGroup,Dialog显示的布局则直接添加到这个ViewGroup中,这样一来,就可以对Dialog的View进行各种动画了!!!再具体的可以自己查看这个库的demo以及源码,可以实现很多厉害的特效!!!
其他
当我们知道可以往decorView中添加View以后,其实我们还可以想到很多其他的玩法,比如点击图片放大,可以直接添加一个View去做动画等等。其实还有一个布局则是Window.ID_ANDROID_CONTENT,也是一个FrameLayout,我们通过setContentView设置的布局就是其唯一的子View,所以我们也可以通过如下代码去添加子视图,视图在Activity的界面之上,不包含状态栏等
final ViewGroup contentView =findViewById(Window.ID_ANDROID_CONTENT);
View tv = LayoutInflater.from(MainActivity.this).inflate(R.layout.decor_layout, contentView, false);
contentView.addView(tv);
https://github.com/huburt-Hu/NewbieGuidehttps://github.com/li-xiaojun/XPopup