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

时间:2019-06-15 07:06:53

标签: android flutter flutter-layout

我想让我的Flutter应用程序占据Android的整个屏幕,同时仍然显示状态栏和导航栏(两者都透明),以实现iOS中的全屏外观。

状态栏的颜色可以轻松更改,但是现在我面临着使应用程序充满屏幕并使导航栏同时透明的问题。

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

default app without modifications

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

1)在MainActivity的onCreate函数中的窗口上设置标记

解决方案来自https://stackoverflow.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来手动获取状态栏和导航栏的高度。此外,这会产生一个与应用程序切换器有关的怪异错误,如下所示(请参阅内容如何跳转以及右上角的调试横幅如何伸展):

solution 1 bug

这个解决方案在我看来似乎很粗略,因为它似乎通过删除窗口inset值来对抗Flutter框架,而且似乎更像是一种变通的解决方法。

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

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

结果:

solution 2 result

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

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

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

9 个答案:

答案 0 :(得分:1)

这可能已经晚了,但是最新的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,
  ),
);

答案 1 :(得分: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
    }
}
  1. 从 main.dart 中删除 SystemChrome.setSystemUIOverlayStyle 命令

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

注意:

  • 如果您将堆栈直接嵌套在某个屏幕的脚手架下, 您可能会在导航栏上方看到您的应用程序绘图。要修复刚刚设置的 脚手架上的以下属性

    resizeToAvoidBottomInset: false

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

    再次覆盖 SystemUIOverlayStyle

答案 2 :(得分:0)

我想我了解您要完成的工作。这样有帮助吗?

您还需要一个Cupertino支架。

https://api.flutter.dev/flutter/cupertino/CupertinoNavigationBar-class.html

如果还有其他想法无法达到您想要的外观。

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

以下对我有用:

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 :(得分:0)

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

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

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

答案 6 :(得分:-1)

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

  1. AppBar()的颜色设置为透明。
  2. extendBeyondAppBar设置为true
  3. elevation设置为0。

例如:

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

答案 7 :(得分:-2)

return Scaffold(
   body: AnnotatedRegion<SystemUiOverlayStyle>(
    value: SystemUiOverlayStyle(
      statusBarColor: Colors.transparent,
      systemNavigationBarColor: Colors.transparent
    ),
    sized: false,
    child: Container(color: Colors.red)
  )
);

答案 8 :(得分:-3)

您尝试过以下方法

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

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

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