将内容布局延伸到状态栏,让应用实现真正的沉浸式

来源:互联网 发布:qt x11中文不显示linux 编辑:程序博客网 时间:2024/06/05 20:00

转载请标明出处:http://blog.csdn.net/edisonchang/article/details/50136735

前段时间应产品需求在应用中加入沉浸式状态栏的UI调整方案。首先得明确一点,只有在大于或等于4.4版本的手机系统才支持沉浸式状态栏效果,至于沉浸式状态栏名称的由来,感兴趣的朋友可以参考为什么在国内会有很多用户把「透明栏」(Translucent Bars)称作 「沉浸式顶栏」。主要的实现方法是将状态栏设为透明,然后设置状态栏的背景和toolbar 一样的颜色,这样看起来整个页面就融合在一起。

国内外的各大厂商在沉浸式展现效果也标新竞异,三星手机的状态栏会有一个黑色渐变蒙层,确保通知栏设为浅色背景时,通知栏图标依然清晰可见;nexus等手机,则会在通知栏上有一个半透明黑色图层,没有渐变效果;而小米、奇酷、乐视等这一类手机状态栏并没有实现蒙层,但图标的颜色会根据状态栏的背景自适应选择黑色或白色。尽管各个厂商都对支持沉浸式方案下了功夫,但是不统一的解决方案在apk开发过程中的适配却是一个令人头疼的事情,当然这不是博文要介绍的重要。

最近发现新版360手机助手也实现了沉浸式状态栏的效果,而且布局延伸到了状态栏,并不是简单的设置状态栏的颜色,实现效果上确实比设置状态栏背景色更加自然,对于不同厂商的rom的适配效果都还不错。

这里写图片描述

网上搜了下发现大家在实现沉浸式状态栏时也有很多困惑,本着科研的态度把沉浸式状态栏的实现再次进行梳理,接下来进入正题,介绍下实现状态栏的步骤,如何将布局延伸到状态栏,先来看两张效果图。

这里写图片描述

左边效果是直接设置状态栏的背景,右边就是将布局延伸到状态栏的效果,下面先看第一种方式,直接上代码,

public class MainActivity extends BaseActivity {    private SystemBarTint mtintManager;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mtintManager = new SystemBarTint(this);        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent = new Intent(MainActivity.this, ImmersiveActivity.class);                MainActivity.this.startActivity(intent);            }        });        setStatusBarColor(Color.parseColor("#ff0099cc"));    }    protected void setStatusBarColor(int colorBurn) {        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {            Window window = setImmerseLayout();            window.setStatusBarColor(colorBurn);        } else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            if (mtintManager != null) {                mtintManager.setStatusBarTintEnabled(true);                mtintManager.setStatusBarTintColor(colorBurn);            }        }    }}

Activity 的实现非常简单,4.4 系统的手机可以借助开源类SystemBarTint 设置状态栏的颜色,实现的关键点在setImmerseLayout方法,将状态栏设为透明FLAG_TRANSLUCENT_STATUS。

 protected Window setImmerseLayout() {        Window window = getWindow();        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);        statusBarHeight = getStatusBarHeight(this.getBaseContext());        return window;    }

布局文件需要设置 android:fitsSystemWindows=”true”,View 的布局容器不包括状态栏区域。这个属性至关重要,关于fitsSystemWindows android api 是这样介绍的,

Boolean internal attribute to adjust view layout based on system
windows such as the status bar. If true, adjusts the padding of this
view to leave space for the system windows. Will only take effect if
this view is in a non-embedded activity.

大体意思是说,这项属性主要应用于系统窗口的视图布局,如状态栏设置。若为true, 则会调整视图的填充空间留出系统窗口,否则就会将布局延伸到状态栏,但这项属性只对于非嵌入式的activity才有效果。 ok,那神马是embedded activity呢?在Stack Overflow 上有一处我认为比较恰当的回答,

An embedded Activity is an Activity which is hosted inside a parent
Activity. The common example being the TabHost/TabActivity design. In
particular, embedded Acitvities reside in the host’s
LocalActivityManager, which is conceptually similar to the
FragmentManager which allows you to display one Activity inside
another.

Given this definition, it is easy to understand why only the host (non
embedded) Activity can support the fitsSystemWindows attribute, as any
embedded Activities are restricted to the area defined by their host.

看到这边,右图效果解决思路基本已经呼之欲出了。如果在布局文件中没有设置或者主动调用api设置android:fitsSystemWindows,那么在设置状态栏透明后,布局就会从状态栏开始布局。实际应用中,我们可以先获取状态栏的高度,

public int getStatusBarHeight(Context context) {        if (statusBarHeight != 0)            return statusBarHeight;        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");        if (resourceId > 0) {            statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);        }        return statusBarHeight;    }

为其设置渐变的背景图,这样就可以在所有手机上都显示渐变,适应通知栏的图标,

viewStatusBarTop = findViewById(R.id.status_bar_top);            RelativeLayout.LayoutParams params2 = (RelativeLayout.LayoutParams) viewStatusBarTop.getLayoutParams();            params2.height = statusBarHeight;            viewStatusBarTop.setLayoutParams(params2);            viewStatusBarTop.setVisibility(View.VISIBLE);

大概就是这些,感兴趣的朋友可以下载源码,多多交流

0 0
原创粉丝点击