如何使用QAndroidApplication::runOnAndroidMainThread修改Android应用的状态栏与导航栏颜色?
如何使用QAndroidApplication::runOnAndroidMainThread修改Android应用的状态栏与导航栏颜色?
刚接触Qt/QML时,在Android上修改状态栏和导航栏颜色确实容易摸不着头脑——尤其是旧的QtAndroid::runOnAndroidThread在Qt6里不再推荐,而新的QAndroidApplication::runOnAndroidMainThread又找不到现成示例。我来一步步带你实现这个需求,保证能跑通!
一、前置准备
首先要确认你使用的是Qt6及以上版本(这个API是Qt6新增的),然后在代码中引入必要的头文件:
#include <QNativeInterface/QAndroidApplication> #include <QtAndroid>
二、编写核心工具函数
我们可以封装一个专门的函数,用来统一设置状态栏和导航栏的颜色,同时处理Android版本兼容性:
void setSystemBarsColor(const QColor& statusBarColor, const QColor& navBarColor, bool isLightStatusBar = false) { // 使用QAndroidApplication::runOnAndroidMainThread将代码调度到Android主线程执行 QNativeInterface::QAndroidApplication::runOnAndroidMainThread([statusBarColor, navBarColor, isLightStatusBar]() -> QVariant { // 获取当前的Android Activity(Qt应用的主Activity) QJniObject activity = QNativeInterface::QAndroidApplication::context(); if (!activity.isValid()) { return QVariant(); } // 获取Activity对应的Window对象(Android中所有UI相关的设置都通过Window操作) QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;"); if (!window.isValid()) { return QVariant(); } // 设置状态栏颜色:传入ARGB格式的颜色值(QColor::rgba()正好返回这个格式) window.callMethod<void>("setStatusBarColor", "(I)V", statusBarColor.rgba()); // 设置导航栏颜色 window.callMethod<void>("setNavigationBarColor", "(I)V", navBarColor.rgba()); // 处理状态栏文字颜色(仅Android 6.0+,即API 23及以上生效) if (QtAndroid::androidSdkVersion() >= 23) { QJniObject decorView = window.callObjectMethod("getDecorView", "()Landroid/view/View;"); if (decorView.isValid()) { int currentFlags = decorView.callMethod<int>("getSystemUiVisibility"); if (isLightStatusBar) { // 开启浅色状态栏文字(适合深色状态栏背景) currentFlags |= QJniObject::getStaticField<int>("android/view/View", "SYSTEM_UI_FLAG_LIGHT_STATUS_BAR"); } else { // 关闭浅色状态栏文字(适合浅色状态栏背景) currentFlags &= ~QJniObject::getStaticField<int>("android/view/View", "SYSTEM_UI_FLAG_LIGHT_STATUS_BAR"); } decorView.callMethod<void>("setSystemUiVisibility", "(I)V", currentFlags); } } return QVariant(); }); }
三、调用方式
方式1:在C++中直接调用
比如在应用启动时就设置好颜色,在main.cpp里:
int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); // 示例:设置状态栏为深蓝色,导航栏为深灰色,状态栏文字为白色(非浅色) setSystemBarsColor(QColor(0x1a, 0x23, 0x7e), QColor(0x21, 0x21, 0x21), false); QQmlApplicationEngine engine; const QUrl url(u"qrc:/main.qml"_qs); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
方式2:注册到QML中调用
如果需要在QML界面里动态调整颜色,可以把这个工具函数封装成QML可调用的类:
- 先创建一个辅助类:
#include <QObject> #include <QColor> class AndroidSystemBarHelper : public QObject { Q_OBJECT public: explicit AndroidSystemBarHelper(QObject *parent = nullptr) : QObject(parent) {} // 标记为Q_INVOKABLE,让QML可以调用 Q_INVOKABLE void setSystemBarsColor(const QColor& statusBarColor, const QColor& navBarColor, bool isLightStatusBar = false) { // 把上面的setSystemBarsColor函数内容复制到这里 } };
- 在
main.cpp中注册这个类到QML:
#include <QQmlEngine> #include <QJSEngine> // ... 其他代码 ... qmlRegisterSingletonType<AndroidSystemBarHelper>("com.example.SystemBarHelper", 1, 0, "SystemBarHelper", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine); Q_UNUSED(scriptEngine); return new AndroidSystemBarHelper(); });
- 在QML中调用:
import QtQuick 2.15 import QtQuick.Controls 2.15 import com.example.SystemBarHelper 1.0 ApplicationWindow { width: 640 height: 480 visible: true title: qsTr("System Bar Demo") Button { text: "切换深色系统栏" onClicked: { SystemBarHelper.setSystemBarsColor("#1a237e", "#212121", false) } } Button { text: "切换浅色系统栏" y: 60 onClicked: { SystemBarHelper.setSystemBarsColor("#f5f5f5", "#e0e0e0", true) } } }
四、注意事项
- 为什么必须用
runOnAndroidMainThread?因为Android的UI操作必须在主线程执行,Qt的这个API帮我们把代码安全地调度到Android主线程,避免崩溃。 - 颜色值必须是ARGB格式,
QColor::rgba()会自动转换为符合要求的整数。 - 状态栏文字颜色的设置仅在Android 6.0(API 23)及以上版本生效,低版本无法修改文字颜色。
- 如果应用使用了全屏/沉浸式模式,可能需要额外设置
SYSTEM_UI_FLAG_LAYOUT_STABLE、SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN等标记,确保颜色设置正常显示。 - 建议在真实Android设备上测试,模拟器可能存在显示差异。
备注:内容来源于stack exchange,提问作者Ahmet97




