Flutter-如何使SnackBar不将FloatingActionButton向上推?

6
如何使Snackbar在弹出时覆盖FloatingActionButton而不是将其向上推? 我已经附上了参考的简化代码。提前感谢您的帮助。
class Screen extends StatefulWidget{

  @override
  State<StatefulWidget> createState() => ScreenState();
}

class ScreenState extends State<Screen>{

  BuildContext context;

  @override
  Widget build(BuildContext context) => Scaffold(
    floatingActionButton: FloatingActionButton(
      onPressed: action,
    ),
    body: Builder(
      builder : (BuildContext context){
        this.context = context;
        return Container();
      }
    )
  );

  action() => Scaffold.of(context).showSnackBar(SnackBar(
    duration: Duration(milliseconds : 1000),
    content: Container(height: 10)
  ));
}
3个回答

15

你可以将SnackBarbehavior属性设置为SnackBarBehavior.floating,这将在其他小部件上方显示Snackbar

这应该就可以了 -

class Screen extends StatefulWidget{

  @override
  State<StatefulWidget> createState() => ScreenState();
}

class ScreenState extends State<Screen>{

  BuildContext context;

  @override
  Widget build(BuildContext context) => Scaffold(
    floatingActionButton: FloatingActionButton(
      onPressed: action,
    ),
    body: Builder(
      builder : (BuildContext context){
        this.context = context;
        return Container();
      }
    )
  );

  action() => Scaffold.of(context).showSnackBar(SnackBar(
    duration: Duration(milliseconds : 1000),
    content: Container(height: 10)
    behavior: SnackBarBehavior.floating, // Add this line
  ));
}

查看此链接以获取更多信息。


谢谢。好的解决方案。有没有办法使它叠加显示? - stackunderflow
请问您所说的“overlaid”是什么意思?因为我提供的解决方案已经将“SnackBar”显示在其他小部件之上了。 - thedarthcoder
重叠,就像在“堆栈”中一样。 - stackunderflow
1
据我所知,使用 SnackBar 小部件无法直接实现。您可能需要创建自己的自定义小部件,然后将其包装在 Stack 中。 此外,根据 Google 官方的Material Design Guidelines,不建议使用重叠的 SnackBar - thedarthcoder
1
另外,如果我的答案解决了您的问题,请点击大复选框将其接受为答案。干杯! - thedarthcoder
你的评论足以回答问题,不需要展示代码。无论如何感谢您。 - Abdul Qadir

2

只需使用多个 Scaffold。用一个外部的 Scaffold 包装内部的 Scaffold。将所有属于内部的东西,如 bodyappBarbottomNavigationBarfloatingActionButton 等放在内部。从外部的 bodyBuildContext 中调用 showSnackBar。如果有,将内部的 drawer 移到外部以使其位于 SnackBar 上方。

如果您喜欢像经典吐司一样弹出 SnackBar,请查看 Siddharth Patankar 的答案。也感谢他。

以下是我的答案的简化代码。

  @override
  Widget build(BuildContext context) => Scaffold(
    drawer : Drawer(child: Container()),
    body: Builder(
      builder : (BuildContext context){
        this.context = context;
        return Scaffold(
          body: Container(),
          floatingActionButton: FloatingActionButton(
            onPressed: () => Scaffold.of(context).showSnackBar(SnackBar(
              duration: Duration(milliseconds : 1000),
              content: Container(height: 30),
            )),
          ),
        );
      }
    )
  );

1

SnackBar重叠FAB(基础)

enter image description here

要使 SnackBar 重叠在 FAB 上,FAB 应该放置在嵌套的 Scaffold 上。
class BasicOverlapFAB extends StatelessWidget {
  const BasicOverlapFAB();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Basic Overlap'),
      ),
      body: Scaffold( // ← Nested
        body: Center(child: Text('SnackBar will overlap FAB'),),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.keyboard_double_arrow_down),
          onPressed: () => ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('This overlaps the FAB'),)
          ),
        ),
      )
    );
  }
}

这是因为 SnackBar 显示在最接近 ScaffoldMessenger 的最高层级 Scaffold 上。默认情况下,最近的 ScaffoldMessenger 包含在 MaterialApp 中。
在上面的代码中,显示 SnackBar 的 Scaffold 是父级/高于带有 FAB 的 Scaffold,因此 Snack 会覆盖 FAB。
MaterialApp
  ScaffoldMessenger
    Scaffold ← Snacks here
      Scaffold
        FAB

嵌套的ScaffoldsScaffoldMessengers

SnackBar overlap FAB

这个例子有几个嵌套的 Scaffolds。

Scaffolds 就像玻璃窗格一样。我们可以将一个窗格叠加在另一个上面。我们可以在每个窗格上显示 FABs、SnackBars 和其他小部件。

为了更容易看到 Scaffolds 的层次,每个 Scaffold 都较小,并用不同的颜色轮廓线标出:蓝色、绿色、红色。红色是最下面的。(嵌套的窗格在下面。)

Scaffolds 默认不提供 ScaffoldMessenger,但 MaterialApp 提供了默认的 ScaffoldMessenger。大多数情况下,我们与这个默认的“根”ScaffoldMessenger交互,但我们也可以添加自己的。

在这个例子中,对于每个 Scaffold 层(AnotherScaffold 自定义类),我们手动添加了它自己的 ScaffoldMessenger。每个层还有一个 FAB,在其自己的 ScaffoldMessenger 上显示 SnackBars。

在模拟器中复制/粘贴并尝试操作,以了解 Scaffolds/ScaffoldMessengers 如何形成层次结构,如何重叠和相互作用。

class NestedScaffoldsPage extends StatelessWidget {
  const NestedScaffoldsPage();

  @override
  Widget build(BuildContext context) {
    return Container( // unnecessary container just for border color / educational visibility
      decoration: BoxDecoration(
          border: Border.all(color: Colors.blue)
      ),
      child: Scaffold(// Root Scaffold for FAB #0
        appBar: AppBar(
          title: Text('Nested Scaffolds'),
        ),
        body: AnotherScaffold(// Nested Scaffold & FAB #1
          level: 1,
          color: Colors.green,
          body: AnotherScaffold(// Nested Scaffold & FAB #2
            level: 2,
            color: Colors.red,
            body: Center(child: Text('3 Total Scaffolds')),
          ),
        ),
        floatingActionButton: FloatingActionButton( // FAB #0
          child: Text('0'),
          onPressed: () => ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Snack level 0'),
                duration: const Duration(seconds: 2),
                //behavior: SnackBarBehavior.floating, // SnackBar will show above FAB
                //behavior: SnackBarBehavior.fixed, // default, pushes FAB up
              )
          ),
        ),
      ),
    );
  }
}

class AnotherScaffold extends StatelessWidget {
  final int level;
  final Widget body;
  final Color color;
  final GlobalKey<ScaffoldMessengerState> smState;

  AnotherScaffold({
    required this.level,
    required this.color,
    required this.body,
  }) : smState = GlobalKey<ScaffoldMessengerState>();
  /// This GlobalKey, given to a ScaffoldMessenger, will uniquely identify that
  /// ScaffoldMessenger.  We can then use it to show SnackBars.

  @override
  Widget build(BuildContext context) {
    return ScaffoldMessenger(
      key: smState, // use this key to show SnackBars on this ScaffoldMessenger
      child: Container( // unnecessary container just for border color / educational visibility
        margin: EdgeInsets.all(5),
        decoration: BoxDecoration(
          border: Border.all(color: color),
        ),
        child: Scaffold(
          body: body,
          floatingActionButton: Padding(
            padding: EdgeInsets.only(right: (level) * 40),
            child: FloatingActionButton(
              heroTag: GlobalKey(), // unique tag req'd for multiple FABs
              backgroundColor: color,
              child: Text('$level'),
              onPressed: () => // using smState key to show a SnackBar on that ScaffoldMessenger
                  smState.currentState!.showSnackBar(SnackBar(
                    duration: Duration(milliseconds: 2500),
                    content: Text('Snack level $level'),
                  )),
            ),
          ),
        ),
      ),
    );
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接