Flutter 沉浸式状态栏实现及Splash屏幕

Android原生中实现沉浸式状态栏很普遍。那在Flutter中如何实现呢。下面就大概总结一下。
开发环境如下:

[] Flutter (Channel stable, 1.22.6, on Mac OS X 10.14.5 18F132 darwin-x64,
    locale zh-Hans-CN)

[] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[] Xcode - develop for iOS and macOS (Xcode 11.3.1)
[] Android Studio (version 4.1)

使用AndroidStudio新建一个Flutter项目,这里就不展开说了
然后打开Android部分的AndroidManifest文件,默认会有一个MainActivity的定义

<activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
           
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
           
            <meta-data
              android:name="io.flutter.embedding.android.SplashScreenDrawable"
              android:resource="@drawable/splash_background"/>
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

样式一:Activity的样式定义为LaunchTheme,主要就是App启动时避免出现出现白屏或黑屏
样式二:io.flutter.embedding.android.NormalTheme的样式,这个就是Android进程启动后指定给Activity的样式,Flutter UI初始化后,这个样式会一直作为Flutter UI的背景存在。
样式三:闪屏的图片设置io.flutter.embedding.android.SplashScreenDrawable,这个图片作为样式一和样式三的过渡。为了在Flutter UI展示之前继续显示Launch 屏幕,所以这个图片要和Launch的一样。
下面就直接贴一下样式的定义:
LaunchTheme, 使用Activity展示一个启动页面,当Flutter开始绘制时,自动移除这个样式

<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
        
        <!--Android 5.x开始需要关闭状态栏半透明,并把颜色设置透明,否则导航栏会呈现系统默认的浅灰色-->
        <!--关闭状态栏半透明效果-->
        <item name="android:windowTranslucentStatus">false</item>
        <!--设置状态栏为透明-->
        <item name="android:statusBarColor">@android:color/transparent</item>
        <!--设置导航栏半透明-->
        <item name="android:windowTranslucentNavigation">true</item>
        <item name="android:fitsSystemWindows">true</item>
        <item name="android:windowBackground">@drawable/launch_background</item>
        <item name="android:windowFullscreen">true</item>
    </style>

NormalTheme,跟LaunchTheme相比,就是没有不需要全屏,然后要换一个所有页面使用的背景,相比Launch可能是少一个logo的背景图,当然这个要看具体需求。

<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
        
        <!--Android 5.x开始需要关闭状态栏半透明,并把颜色设置透明,否则导航栏会呈现系统默认的浅灰色-->
        <!--关闭状态栏半透明效果-->
        <item name="android:windowTranslucentStatus">false</item>
        <!--设置状态栏为透明-->
        <item name="android:statusBarColor">@android:color/transparent</item>
        <!--设置导航栏半透明-->
        <item name="android:windowTranslucentNavigation">true</item>
        <item name="android:fitsSystemWindows">true</item>
        <item name="android:windowBackground">@drawable/normal_background</item>
    </style>

如果需要让Flutter的页面都直接使用Normal中设置的背景图,那么需要在MainActivity中覆盖一下如下方法,让Widget的本身的背景是透明的。

override fun getTransparencyMode(): TransparencyMode {
        return TransparencyMode.transparent
    }

如果想让这个App都是透明的,也就是直接能看到桌面壁纸的话,需要覆盖如下方法。

override fun getBackgroundMode(): FlutterActivityLaunchConfigs.BackgroundMode {
        return FlutterActivityLaunchConfigs.BackgroundMode.transparent;
    }

但此方法不建议使用,官方文档中说会严重影响性能。

/**
     * The mode of {@code FlutterActivity}'s background, either {@link BackgroundMode#opaque} or
     * {@link BackgroundMode#transparent}.
     *
     * <p>The default background mode is {@link BackgroundMode#opaque}.
     *
     * <p>Choosing a background mode of {@link BackgroundMode#transparent} will configure the inner
     * {@link FlutterView} of this {@code FlutterActivity} to be configured with a {@link
     * FlutterTextureView} to support transparency. This choice has a non-trivial performance
     * impact. A transparent background should only be used if it is necessary for the app design
     * being implemented.
     *
     * <p>A {@code FlutterActivity} that is configured with a background mode of {@link
     * BackgroundMode#transparent} must have a theme applied to it that includes the following
     * property: {@code <item name="android:windowIsTranslucent">true</item>}.
     */
    @NonNull
    public NewEngineIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode) {
      this.backgroundMode = backgroundMode.name();
      return this;
    }

以上就是Android端的设置,我们还需要再Flutter中进行相应的设置。

runApp(new MyApp());
//必须写在组件渲染(也就是runApp方法)之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。
  if (defaultTargetPlatform == TargetPlatform.android) {
    SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
      statusBarBrightness: Brightness.dark,
    );
    SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  } else if (defaultTargetPlatform == TargetPlatform.iOS) {
    //手机的状态栏默认为打开的
    //判断是否为苹果手机。如果是,并且padding top不为0即为x系列
    //其他系列关闭状态栏
    if (MediaQuery.of(_context).padding.top == null ||
        MediaQuery.of(_context).padding.top == 0) {
    SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.top]);
    }
    SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
      statusBarBrightness: Brightness.light,
      statusBarIconBrightness: Brightness.dark,
    );
    SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  }

以上即为全部设置。后续有更好的方式再继续更新。

2021年07月13日更新:
关于状态栏背景色和文本颜色设置,分为两种情况

  1. 无AppBar的情况
    直接在main.dart中配置SystemUiOverlayStyle即可
runApp(MyApp());
//必须放着runApp之后执行,在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值
	SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
      statusBarBrightness: Brightness.light,
      statusBarIconBrightness: Brightness.light, //light:文本为白色,dark:文本为黑色
      systemNavigationBarColor: Colors.white,
      systemNavigationBarDividerColor: Colors.transparent,
      systemNavigationBarIconBrightness: Brightness.dark,
    );
    SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  1. 有AppBar的情况
    需要在widget中的appbar中进行配置

同无Appbar一样,先要配置状态栏透明


runApp(MyApp());
 SystemUiOverlayStyle systemUiOverlayStyle =
    SystemUiOverlayStyle(statusBarColor: Colors.transparent);
    SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);

然后在appbar中进行配置

appBar: AppBar(
              backgroundColor: Colors.transparent, //把appbar的背景色改成透明
              elevation: 0,   //取消appbar的阴影
              brightness: Brightness.light, //需要注意这里,light:状态栏文字黑色,dark:状态栏文字白色
              title: Text(widget.title),
            ),
            body: 

如果不需要状态栏(比如splash界面)

//全屏,不显示状态栏,也不现实底部虚拟键盘
SystemChrome.setEnabledSystemUIOverlays([]);

//想要控制它显示 :
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.top]); //top : bottom
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值