最简单改变状态栏文字及背景颜色的方法

本文介绍了如何使用AndroidX官方提供的WindowInsetsControllerCompat API,优雅地处理状态栏字体颜色和背景颜色的修改,避免反射代码和兼容性问题。通过示例代码展示了在不同模式下设置状态栏和导航栏颜色的方法,简化了Android应用的UI适配工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

我们知道,Android的状态栏(StatusBar)是可以由开发者自行更改背景颜色的,至于文字颜色,不能直接由自己修改色值,而是黑白两种颜色,对应的是Light和Dark两种全局主题模式。

为了良好的用户体验,我们在状态栏背景为深色时,需要给予白色字体,反之亦然。比如这样:

在这里插入图片描述

然而,有些时候我们在Light Mode下并不需要黑色字体,就需要自己手动修改了。

方法

以前我们修改状态栏相关的内容,都是去找各种反射代码,或者各种封装好的StatusBarUtil之类的,不仅代码不优雅,还容易出现千奇百怪的兼容性问题,不利于维护。

如今,谷歌官方已经给出了解决方案,一切尽在AndroidX。直接看代码:

import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsControllerCompat;

public class MainActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 修改状态栏字体颜色,用AndroidX官方兼容API
        WindowInsetsControllerCompat wic = ViewCompat.getWindowInsetsController(getWindow().getDecorView());
        if (wic != null) {
            // true表示Light Mode,状态栏字体呈黑色,反之呈白色
            wic.setAppearanceLightStatusBars(false);
        }

        // 修改状态栏背景颜色,还是通用API,这个比较简单
        getWindow().setStatusBarColor(...);
    }
}

引申一下,包括修改底部导航栏,都是类似的:

// 修改导航栏按钮颜色
wic.setAppearanceLightNavigationBars(false);
// 修改导航栏背景色
getWindow().setNavigationBarColor();

其他

要使用 WindowInsetsControllerCompat 这个类,只需要引入 androidx.core 即可,版本号随意,按最新的来。

但如果你已经依赖了 androidx.appcompatcom.google.android.material ,就不需要单独引入core了,因为前两者已经包含了core:

dependencies {
    // 直接依赖
    implementation "androidx.core:core:1.5.0"
    // 间接依赖
    implementation "androidx.appcompat:appcompat:1.3.1"
    // or
    implementation "com.google.android.material:material:1.4.0"
}

其实我们感兴趣也可以简单看看源码。首先会根据不同的系统版本号返回对应的实现:

@Nullable
public static WindowInsetsControllerCompat getWindowInsetsController(@NonNull View view) {
    if (Build.VERSION.SDK_INT >= 30) {
        return ViewCompat.Api30Impl.getWindowInsetsController(view);
    } else {
        Context context = view.getContext();
        while (context instanceof ContextWrapper) {
            if (context instanceof Activity) {
                Window window = ((Activity) context).getWindow();
                return window != null ? WindowCompat.getInsetsController(window, view) : null;
            }
            context = ((ContextWrapper) context).getBaseContext();
        }
        return null;
    }
}

然后再根据对应的版本调用相应的实现接口:

private static class Impl {
    Impl() {
        //privatex
    }

    // ... 省略其他

    public boolean isAppearanceLightStatusBars() {
        return false;
    }

    public void setAppearanceLightStatusBars(boolean isLight) {
    }

    public boolean isAppearanceLightNavigationBars() {
        return false;
    }

    public void setAppearanceLightNavigationBars(boolean isLight) {
    }
}

@RequiresApi(20)
private static class Impl20 extends Impl {...}

@RequiresApi(23)
private static class Impl23 extends Impl20 {...}

@RequiresApi(26)
private static class Impl26 extends Impl23 {...}

@RequiresApi(30)
private static class Impl30 extends Impl {...}

所以这就是为什么此类可以兼容不同版本而不用开发者担心兼容性问题了,有效缓解碎片化的情况。我们从中也可看出一些细微差异,比如API 26之前都是逐代继承兼容,但到了30就重新实现了一遍接口,说明30做了一些改动较大的优化。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值