android4.4 状态栏,Android4.4及以上版本实现状态栏与顶栏同色

在Android中实现状态栏与顶栏同色,可以增加应用的美观性,提升用户体验。那么这一点是如何实现的呢?

目前,比较常用的是github上一个叫做SystemBarTint的库。但是在实际使用的过程中,当与碎总的SwipeBackLayout滑

动返回一起使用的时候,会发现通知栏并不能和当前页面一起被滑走,在StatusBar与ActionBar连接的地方会有很明显的撕裂感,非常影响用户

体验。所以在我们自己的项目中放弃了这种实现方式并寻求其他解决方案,最终通过阅读SwipeBackLayout源码和SystemBarTint源码

找到了解决方案,实现了状态栏和顶栏同色与滑动返回的完美结合。

首先我们通过SystemBarTint的源码分析来搞明白状态栏和变色是如何实现的/**

* Constructor. Call this in the host activity onCreate method after its

* content view has been set. You should always create new instances when

* the host activity is recreated.

*

* @param activity The host activity.

*/

@TargetApi(19)

public SystemBarTintManager(Activity activity) {

Window win = activity.getWindow();

ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

// check theme attrs

int[] attrs = {android.R.attr.windowTranslucentStatus,

android.R.attr.windowTranslucentNavigation};

TypedArray a = activity.obtainStyledAttributes(attrs);

try {

mStatusBarAvailable = a.getBoolean(0, false);

mNavBarAvailable = a.getBoolean(1, false);

} finally {

a.recycle();

}

// check window flags

WindowManager.LayoutParams winParams = win.getAttributes();

int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;

if ((winParams.flags & bits) != 0) {

mStatusBarAvailable = true;

}

bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;

if ((winParams.flags & bits) != 0) {

mNavBarAvailable = true;

}

}

mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable);

// device might not have virtual navigation keys

if (!mConfig.hasNavigtionBar()) {

mNavBarAvailable = false;

}

if (mStatusBarAvailable) {

setupStatusBarView(activity, decorViewGroup);

}

if (mNavBarAvailable) {

setupNavBarView(activity, decorViewGroup);

}

}

可以看到在27~31行通过条件判断首先设置statusbar为透明(只有Android4.4及以上的系统才可以设置statusbar为透明,这也

是状态栏变色只在Android4.4及以上系统有效的原因),将statusbar设置为透明之后,statusbar下边的那一层黑条就不见了,当前

页面的内容也就会顶到屏幕最上边了(statusbar和navigationbar其实是两个window)。接下来,我们再来看一段代码private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {

mStatusBarTintView = new View(context);

LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());

params.gravity = Gravity.TOP;

if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {

params.rightMargin = mConfig.getNavigationBarWidth();

}

mStatusBarTintView.setLayoutParams(params);

mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);

mStatusBarTintView.setVisibility(View.GONE);

decorViewGroup.addView(mStatusBarTintView);

}

通过这一段代码可以看出,SystemBarTint通过给decorview add了一个和statusbar高度一样的view进去。

至此,我们应该知道SystemBarTint是如何实现状态栏变色的了,接下来我们再看看SwipeBackLayout的源码

首先,我们来看SwipeBackActivity这个类public class SwipeBackActivity extends ActionBarActivity implements SwipeBackActivityBase {

private SwipeBackActivityHelper mHelper;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mHelper = new SwipeBackActivityHelper(this);

mHelper.onActivityCreate();

}

@Override

protected void onPostCreate(Bundle savedInstanceState) {

super.onPostCreate(savedInstanceState);

mHelper.onPostCreate();

}

@Override

public View findViewById(int id) {

View v = super.findViewById(id);

if (v == null && mHelper != null)

return mHelper.findViewById(id);

return v;

}

@Override

public SwipeBackLayout getSwipeBackLayout() {

return mHelper.getSwipeBackLayout();

}

@Override

public void setSwipeBackEnable(boolean enable) {

getSwipeBackLayout().setEnableGesture(enable);

}

@Override

public void scrollToFinishActivity() {

getSwipeBackLayout().scrollToFinishActivity();

}

}

可以看到在14行的地方有一个mHelper.onPostCreate(),我们接着往下看public class SwipeBackActivityHelper {

private Activity mActivity;

private SwipeBackLayout mSwipeBackLayout;

public SwipeBackActivityHelper(Activity activity) {

mActivity = activity;

}

@SuppressWarnings("deprecation")

public void onActivityCreate() {

mActivity.getWindow().setBackgroundDrawable(new ColorDrawable(0));

mActivity.getWindow().getDecorView().setBackgroundDrawable(null);

mSwipeBackLayout = (SwipeBackLayout) LayoutInflater.from(mActivity).inflate(

me.imid.swipebacklayout.lib.R.layout.swipeback_layout, null);

mSwipeBackLayout.addSwipeListener(new SwipeBackLayout.SwipeListener() {

@Override

public void onScrollStateChange(int state, float scrollPercent) {

}

@Override

public void onEdgeTouch(int edgeFlag) {

}

@Override

public void onScrollOverThreshold() {

}

});

}

public void onPostCreate() {

mSwipeBackLayout.attachToActivity(mActivity);

}

public View findViewById(int id) {

if (mSwipeBackLayout != null) {

return mSwipeBackLayout.findViewById(id);

}

return null;

}

public SwipeBackLayout getSwipeBackLayout() {

return mSwipeBackLayout;

}

}

可以发现在33行的位置有一个mSwipeBackLayout.attachToActivity(mActivity),我们接着看下去public void attachToActivity(Activity activity) {

mActivity = activity;

TypedArray a = activity.getTheme().obtainStyledAttributes(new int[] {

android.R.attr.windowBackground

});

int background = a.getResourceId(0, 0);

a.recycle();

ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();

ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);

decorChild.setBackgroundResource(background);

decor.removeView(decorChild);

addView(decorChild);

setContentView(decorChild);

decor.addView(this);

}

终于,我们找到了最初始的位置,通过这一段代码,我们会发现SwipeBackLayout的原理其实就是获取到当前页面的DecorView然后

再获取到这棵view树位于0位置的view并将其移除,之后再把SwipeBackLayout(通过源码可以知道这个Layout是继承自

FrameLayout的) add到DecorView里边来。

综合分析了SystemBarTint和SwipebackLayout的源码之后,我们也就知道为什么statusbar不能一起划走的原因了,

因为SystemBarTint是给DecorView

add了一个和statusbar同高的view,而SwipeBackLayout也是DecorView的子view,这两个view在同一层次上,

所以不能一起滑走。知道原因之后,解决方案也就浮出了水面,我们可以在把那个view

add到SwipwBacklayout里边来,这样子就可以一起滑走了。下面代码是我们项目里边的实现方式@TargetApi(Build.VERSION_CODES.KITKAT)

protected void setSystemBarTransparent() {

Window window = getWindow();

WindowManager.LayoutParams layoutParams = window.getAttributes();

layoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;

if (immerseNavigationBar() && !SmartBarUtils.isMeizu()) {

layoutParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;

}

window.setAttributes(layoutParams);

if (shouldHackStatusBarTransparent()) {

hackStatusBarTransparent();

setContentPadding();

}

}

protected void setContentPadding() {

int actionBarHeight = mHasActionBarHeight ? CommonUtils.getActionBarHeight(this) : 0;

((ViewGroup) findViewById(android.R.id.content)).getChildAt(0).setPadding(0,

CommonUtils.getStatusBarHeight(this) + actionBarHeight, 0, 0);

}

protected void hackStatusBarTransparent() {

Window window = getWindow();

ViewGroup contentFrame = (ViewGroup) window.getDecorView().findViewById(

android.R.id.content);

View hackView = new View(this);

setStatusViewBackground(hackView);

contentFrame.addView(hackView, ViewGroup.LayoutParams.MATCH_PARENT,

CommonUtils.getStatusBarHeight(this));

}

可以看到我们是把这个view add到content这一层了,也不再需要用到SystemBarTint这个库了。

最后通过hierarchyviewer工具load出来一个view布局很容易看明白这个问题,截图如下

132I260C-0.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值