【问题标题】:Unable to display SnackBar无法显示 SnackBar
【发布时间】:2019-08-28 07:50:59
【问题描述】:

我是 Flutter 的新手,只是想了解这个框架的工作原理。所以下面的代码没有多大意义。

我试图通过调用子小部件在应用加载后立即显示小吃店。

代码如下:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Demo')),
        body: GetSnackBarWidget(),
      ),
    );
  }
}

class GetSnackBarWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final snackBar = SnackBar(content: Text("SnackBar"));
    Scaffold.of(context).showSnackBar(snackBar);
    return Text("returned");
  }
}

但我得到以下异常:

I/flutter ( 3781): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ I/flutter ( 3781): The following assertion was thrown building GetSnackBarWidget(dirty): I/flutter ( 3781): setState() or markNeedsBuild() called during build. I/flutter ( 3781): This Scaffold widget cannot be marked as needing to build because the framework is already in the I/flutter ( 3781): process of building widgets. A widget can be marked as needing to be built during the build phase I/flutter ( 3781): only if one of its ancestors is currently building. This exception is allowed because the framework I/flutter ( 3781): builds parent widgets before children, which means a dirty descendant will always be built. I/flutter ( 3781): Otherwise, the framework might not visit this widget during this build phase. I/flutter ( 3781): The widget on which setState() or markNeedsBuild() was called was: I/flutter ( 3781): Scaffold(dependencies: [_LocalizationsScope-[GlobalKey#33728], Directionality, _InheritedTheme, I/flutter ( 3781): MediaQuery], state: ScaffoldState#dbc9e(tickers: tracking 2 tickers)) I/flutter ( 3781): The widget which was currently being built when the offending call was made was: I/flutter ( 3781): GetSnackBarWidget(dirty)

有人可以详细解释发生了什么吗?

【问题讨论】:

    标签: flutter


    【解决方案1】:

    本质上,您不能在构建小部件时直接调用 Scaffold.of(context).showSnackBar(snackBar)。如果您有一个按钮,则可以将其用于 onPressed 方法,因为在构建小部件时不会立即调用它,而是在其他一些异步事件之后调用它。

    如果您要立即展示小吃栏,解决方案是告诉应用在构建所有小部件后立即显示小吃栏。您可以通过使用 WidgetsBinding.instance.addPostFrameCallback() 添加一个回调方法来显示小吃栏,如下所示:

    final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
    
    ...
    
        return Scaffold(
          key: _scaffoldKey,
    
    ...
             //when you want to display the snackbar during a build method, 
             //use addPostFrameCallback
    
             WidgetsBinding.instance.addPostFrameCallback((_) => _showMessage('snackbar message'));
    
    ...
    
    void _showMessage(String message) {
      _scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message),));
    }
    

    【讨论】:

    • 成功了。如果我理解正确,问题是我正在调用一个仍处于构建状态的小部件(脚手架)?另外,能否请您提供一些可以详细解释WidgetsBinding.instance.addPostFrameCallback_scaffoldKey.currentState 的链接。我试图搜索很多但没有运气。谢谢。
    • 这里有一个类似的例子 - stackoverflow.com/questions/51458885/… - 这可能是我最初得到答案的地方
    【解决方案2】:

    首先,将SnackBar 放在build() 方法中并不是一个好主意。您可以根据需要尝试在应用启动时显示SnackBar 的解决方案。

    class _HomePageState extends State<HomePage> {
      GlobalKey<ScaffoldState> _key = GlobalKey();
    
      @override
      void initState() {
        super.initState();
        Timer.run(() => _key.currentState.showSnackBar(SnackBar(content: Text("Hi"),)));
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          key: _key,
          appBar: AppBar(title: Text("App")),
          body: Container(),
        );
      }
    }
    

    【讨论】:

      【解决方案3】:

      如果您想在小部件中显示 SnackBar,您必须遵循以下代码:

      class _DelayWidgetState extends State<DelayWidget> {
        @override
        Widget build(BuildContext context) {
          return new Scaffold(
            appBar: new AppBar(
              title: new Text("SbackBar Functionality"),
            ),
            body: new Builder(builder: (BuildContext context) {
              return new RaisedButton(
                onPressed: () {
                  Scaffold.of(context).showSnackBar(
                    new SnackBar(
                      content: new Text("Sending Message"),
                    ),
                  );
                },
                child: new Text("Click"),
              );
            }),
          );
        }
      }
      

      在上面的示例中,作为 Scaffold.of() 添加的另一个 Builder 使用不包含 Scaffold 的上下文调用。

      【讨论】:

        猜你喜欢
        • 2015-11-28
        • 2020-05-16
        • 1970-01-01
        • 2019-12-15
        • 2023-03-07
        • 2017-03-27
        • 1970-01-01
        • 1970-01-01
        • 2016-04-05
        相关资源
        最近更新 更多