如何让 Flutter 应用在​​ android 导航栏后面绘制并使导航栏完全透明?

Posted

技术标签:

【中文标题】如何让 Flutter 应用在​​ android 导航栏后面绘制并使导航栏完全透明?【英文标题】:How to make flutter app draw behind android navigation bar and make navigation bar fully transparent? 【发布时间】:2019-10-29 16:21:20 【问题描述】:

我想让我的 Flutter 应用在​​ android 中占据整个屏幕,同时仍然显示状态栏和导航栏,并且它们都是透明的,以实现ios 中的全屏外观。

状态栏颜色可以轻松更改,但现在我遇到了让应用填满屏幕并同时使导航栏透明的问题。

默认情况下,应用根本不绘制在导航栏下方(我已将状态栏颜色设置为透明):

以下是我尝试过的一些解决方案:

1) 在MainActivity的onCreate函数中设置窗口的flags

从这里获取的解决方案:https://***.com/a/31596735

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
  window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, 
    WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)

这种实现了我想要的,但它有几个问题。 MediaQuery 中的 padding 和 inset 值现在为 0,因此我必须通过使用 MethodChannel 手动获取状态栏和导航栏高度。此外,这会产生一个关于应用程序切换器的奇怪错误,如下所示(查看内容如何跳转和右上角的调试横幅被拉伸):

2) 在styles.xml中添加半透明导航

<item name="android:windowTranslucentNavigation">true</item>

结果:

这是最接近我想要实现的目标。 MediaQuery.of(context).padding.top 正确显示顶部填充,MediaQuery.of(context).viewInsets.bottom 正确显示导航栏的高度。应用程序切换器中也没有奇怪的错误。唯一的问题是导航栏是半透明的而不是透明的。

这是上面显示的示例应用程序的存储库:https://github.com/CZX123/navbar

如果 Flutter 能够开箱即用地提供此功能,那就太好了。但事实并非如此,那么还有其他更好的方法来实现这一点吗?

更新

看来我们得等 Flutter 团队正式实现这个功能了:https://github.com/flutter/flutter/issues/40974https://github.com/flutter/flutter/issues/34678

这条评论也完美总结了Android中的当前行为:https://github.com/flutter/flutter/issues/34678#issuecomment-536028077

【问题讨论】:

这能回答你的问题吗? Transparent bottom navigation bar in flutter 不,这不是关于这个的。这个问题是关于实际系统 UI 导航(如 Android Q 中介绍的)在 Flutter 中无法正确呈现。 有没有找到让系统导航栏透明的解决方案? 【参考方案1】:

我通过编辑以下文件轻松实现了整个应用的透明效果

1.在android/app/build.gradle

中添加以下行
dependencies 
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.5.0-beta01' //add this line

2.在您的 android/app/src/main/kotlin/com///MainActivity.kt 中添加以下内容

import androidx.core.view.WindowCompat //add this line
import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity() 
    //add the following block of code
    override fun onPostResume() 
        super.onPostResume()
        WindowCompat.setDecorFitsSystemWindows(window, false)
        window.navigationBarColor = 0 //for transparent nav bar
        window.statusBarColor = 0 //for transparent status bar
    

    从你的 main.dart 中删除 SystemChrome.setSystemUIOverlayStyle 命令

    运行 flutter clean 并重新运行您的应用。

注意:

如果您在某些屏幕的脚手架下直接嵌套堆栈, 您可能会在导航栏上方看到您的应用程序绘图。解决刚刚设置的问题 脚手架上的以下属性

resizeToAvoidBottomInset: false

如果您使用 appbar 或 safeArea,您可能需要使用 AnnotatedRegion

再次覆盖 SystemUIOverlayStyle

【讨论】:

【参考方案2】:

Flutter 2.5.0之后:

这对我来说就像魅力一样!

在您的main() 中粘贴以下代码:

//Setting SysemUIOverlay
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
    systemStatusBarContrastEnforced: true,
    systemNavigationBarColor: Colors.transparent,
    systemNavigationBarDividerColor: Colors.transparent,
    systemNavigationBarIconBrightness: Brightness.dark,
    statusBarIconBrightness: Brightness.dark)
);
    
//Setting SystmeUIMode
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge, overlays: [SystemUiOverlay.top]);

【讨论】:

【参考方案3】:

虽然我不知道这种方法可能会导致哪些副作用,但我相信它可以解决您的问题:

Scaffold(
  primary: false,
  appBar: AppBar(
    primary: false,
    // ...
  ),
  // ...
)

将 Scaffold 和 AppBar 的主要属性都设置为 false 会删除它们的内部 SafeArea,这会将它们呈现在系统 UI 后面。

【讨论】:

【参考方案4】:

以下内容对我有用:

build.gradle(应用程序)

implementation 'androidx.core:core-ktx:1.5.0-rc01'

MainActivity.kt

class MainActivity: FlutterActivity() 

    override fun onPostResume() 
        super.onPostResume()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 
            WindowCompat.setDecorFitsSystemWindows(window, false)
            window.navigationBarColor = 0
        
    

ma​​in.dart

void main() 
  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark.copyWith(
    systemNavigationBarColor: Colors.transparent,
    statusBarColor: Colors.transparent,
  ));
  runApp(MyApp());

灵感来自https://github.com/flutter/flutter/issues/40974

【讨论】:

【参考方案5】:

如果仍然存在问题,这里有一个解决方案:

Scaffold(
      backgroundColor: Colors.transparent,
      body: SafeArea()
)

backgroundColor 参数指定整个应用的背景。如果你在脚手架的主体内没有任何东西 - 整个应用程序将只是一个带有状态栏的黑屏。如果您确实在正文中放置了一些小部件 - 状态栏仍然会被着色,就好像您不在应用程序中一样。

【讨论】:

【参考方案6】:

因此,如果您使用的是 Flutter,则过程是:

    AppBar() 颜色设置为透明。 将extendBeyondAppBar 设置为true。 将elevation 设置为0。

举个例子:

    return Scaffold(
        extendBodyBehindAppBar: true,
        appBar: AppBar(
           elevation: 0,
           )

【讨论】:

这与导航栏无关。 这不是正确的答案。这是关于现代 Android 行为,其中在应用程序上绘制了一个小手势导航栏。【参考方案7】:
return Scaffold(
   body: AnnotatedRegion<SystemUiOverlayStyle>(
    value: SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
      systemNavigationBarColor: Colors.transparent
    ),
    sized: false,
    child: Container(color: Colors.red)
  )
);

【讨论】:

【参考方案8】:

这可能有点晚,但是flutter的最新版本,1.12提供了在NavigationBar后面绘制应用程序的功能,所以下面的代码将透明导航栏与应用程序完全扩展在导航栏后面,

Scaffold(
  extendBodyBehindAppBar: true, //this ensures that the body is drawn behind the navigation bar as well
  appBar: AppBar(
    backgroundColor: Colors.transparent,
    title: Text('Transparent Bar'),
  ),
  body: Container(
    color: Colors.blue,
  ),
);

【讨论】:

仅适用于 AppBar,不延伸到系统导航后面【参考方案9】:

你试过下面的方法吗

// to hide only bottom bar:
SystemChrome.setEnabledSystemUIOverlays ([SystemUiOverlay.top]);

// to hide only status bar: 
SystemChrome.setEnabledSystemUIOverlays ([SystemUiOverlay.bottom]);

// to hide both:
SystemChrome.setEnabledSystemUIOverlays ([]);

【讨论】:

我不想隐藏应用栏,我想让它们的背景透明。

以上是关于如何让 Flutter 应用在​​ android 导航栏后面绘制并使导航栏完全透明?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Flutter 让后台应用每天下午 2 点打开一个对话框?

有没有办法让颤动的 webview 使用 android 相机进行文件上传?如何在 webview_flutter 中打开文件选择器?

如何快速掌握Flutter开发核心技能?

Android Flutter:手把手教你如何进行Android 与 Flutter的相互通信

让移动开发更轻松 闲鱼基于Flutter构建跨端APP应用实践

如何在 Android Studio 中为 Flutter 上的小部件测试进入调试模式?