flutter - 在构建期间在将小部件作为参数传递时调用setstate()或markneedsbuild()

标签 flutter exception dart

我有一个带有一些按钮的Stateful Widget。在每次按下按钮时,我想显示不同类型的Dialog。我为Button创建了一个函数,对于每个按钮,我只需调用该函数即可。由于我想在不同的按钮按下时显示不同的Dialog,因此我尝试将Dialog Widget传递为按钮函数的参数,并在onPressed内调用该小部件。当我尝试构建应用程序时,它会显示这些错误。

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building DialogPage(dirty, dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#e6799]], state: _DialogPageState#a5060):
setState() or markNeedsBuild() called during build.

This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: Overlay-[LabeledGlobalKey<OverlayState>#8e4e3]
  state: OverlayState#665ea(entries: [OverlayEntry#1cc53(opaque: true; maintainState: false), OverlayEntry#020ad(opaque: false; maintainState: true), OverlayEntry#1d32e(opaque: false; maintainState: false), OverlayEntry#9a4ae(opaque: false; maintainState: true), OverlayEntry#2728f(opaque: false; maintainState: false), OverlayEntry#33d56(opaque: false; maintainState: true)])
The widget which was currently being built when the offending call was made was: DialogPage
  dirty
  dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#e6799]]
  state: _DialogPageState#a5060
The relevant error-causing widget was: 
  DialogPage file:///C:/Users/imsajib02/AndroidStudioProjects/Flutter/widgets/lib/main.dart:43:32
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3896:11)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3911:6)
#2      State.setState (package:flutter/src/widgets/framework.dart:1168:14)
#3      OverlayState.insertAll (package:flutter/src/widgets/overlay.dart:344:5)
#4      OverlayRoute.install (package:flutter/src/widgets/routes.dart:44:24)
...
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ (2) Exception caught by widgets library ═══════════════════════════════════════════════════
The method 'drive' was called on null.
Receiver: null
Tried calling: drive<Color>(Instance of '_ChainedEvaluation<Color>')
The relevant error-causing widget was: 
  MaterialApp file:///C:/Users/imsajib02/AndroidStudioProjects/Flutter/widgets/lib/main.dart:11:12
════════════════════════════════════════════════════════════════════════════════════════════════════

════════ (3) Exception caught by widgets library ═══════════════════════════════════════════════════
'package:flutter/src/animation/animations.dart': Failed assertion: line 376 pos 15: 'parent != null': is not true.
The relevant error-causing widget was: 
  MaterialApp file:///C:/Users/imsajib02/AndroidStudioProjects/Flutter/widgets/lib/main.dart:11:12
════════════════════════════════════════════════════════════════════════════════════════════════════
D/FlutterView( 3883): Detaching from a FlutterEngine: io.flutter.embedding.engine.FlutterEngine@e78ea39

放置按钮小部件的类:
class DialogPage extends StatefulWidget {

  @override
  _DialogPageState createState() => _DialogPageState();
}

class _DialogPageState extends State<DialogPage> {

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text("Dialogs"),
      ),
      body: Center(
        child: SingleChildScrollView(
          padding: EdgeInsets.only(top: 35),

          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            verticalDirection: VerticalDirection.down,
            children: <Widget>[

              Button("DEFAULT DIALOG", DialogCollection().defaultDialog(context)),
              Button("DIALOG WITH ICON - 1", DialogCollection().customDialog_1(context)),
              Button("Widget", DialogCollection().defaultDialog(context)),
              Button("Widget", DialogCollection().defaultDialog(context)),
              Button("Widget", DialogCollection().defaultDialog(context)),
              Button("Widget", DialogCollection().defaultDialog(context)),
            ],
          ),
        ),
      ),
    );
  }


  Button(String text, Widget widget) {

    return Column(
      children: <Widget>[

        Container(
          width: 230,
          child: RaisedButton(
            onPressed: () {


            },
            shape: RoundedRectangleBorder(
              borderRadius: new BorderRadius.circular(25.0),
              //side: BorderSide(color: Colors.red)
            ),
            color: Colors.blueGrey,
            padding: EdgeInsets.only(top: 12.0, bottom: 12.0, left: 40.0, right: 40.0),
            textColor: Colors.white,
            child: Text(text, textAlign: TextAlign.center ,style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 18,
            ),
            ),
          ),
        ),

        Container(
          height: 35,
        )
      ],
    );
  }
}

我从中调用对话框小部件的类:
class DialogCollection {

  defaultDialog(BuildContext context) {

    return showDialog(
        context: context,
        //barrierDismissible: false, //on touch outside does not dismiss the dialog
        builder: (BuildContext context) {

          return WillPopScope( //WillPopScope stops dismissing dialog on outside touch and back press
            onWillPop: () {
              Navigator.of(context).pop();
              return null;
            },
            child: AlertDialog(

              title: Text("Dialog Title", textAlign: TextAlign.center,),
              titlePadding: const EdgeInsets.all(15.0),
              titleTextStyle: TextStyle(
                color: Colors.redAccent,
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
              content: Text("This is the description of the dialog."),
              actions: <Widget>[

                FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  color: Colors.lightBlueAccent,
                  textColor: Colors.white,
                  child: Text("Yes", style: TextStyle(

                    fontSize: 18,
                  ),
                  ),
                ),

                FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  color: Colors.redAccent,
                  textColor: Colors.white,
                  child: Text("No", style: TextStyle(

                    fontSize: 18,
                  ),
                  ),
                ),
              ],
            ),
          );
        }
    );
  }
}

最佳答案

您可以在下面复制粘贴运行完整代码DialogCollection().defaultDialog(context)表示执行此功能
您可以使用Button调用DialogCollection().defaultDialog来传递函数地址并传递context
程式码片段

Button("DEFAULT DIALOG", DialogCollection().defaultDialog, context)

Button(String text, Function callback, BuildContext context) {
    return Column(
      children: <Widget>[
        Container(
          width: 230,
          child: RaisedButton(
            onPressed: () {
              callback(context);
            },

工作演示

enter image description here

完整的代码
import 'package:flutter/material.dart';

class DialogCollection {
  defaultDialog(BuildContext context) {
    return showDialog(
        context: context,
        //barrierDismissible: false, //on touch outside does not dismiss the dialog
        builder: (BuildContext context) {
          return WillPopScope(
            //WillPopScope stops dismissing dialog on outside touch and back press
            onWillPop: () {
              Navigator.of(context).pop();
              return null;
            },
            child: AlertDialog(
              title: Text(
                "Dialog Title",
                textAlign: TextAlign.center,
              ),
              titlePadding: const EdgeInsets.all(15.0),
              titleTextStyle: TextStyle(
                color: Colors.redAccent,
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
              content: Text("This is the description of the dialog."),
              actions: <Widget>[
                FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  color: Colors.lightBlueAccent,
                  textColor: Colors.white,
                  child: Text(
                    "Yes",
                    style: TextStyle(
                      fontSize: 18,
                    ),
                  ),
                ),
                FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  color: Colors.redAccent,
                  textColor: Colors.white,
                  child: Text(
                    "No",
                    style: TextStyle(
                      fontSize: 18,
                    ),
                  ),
                ),
              ],
            ),
          );
        });
  }
}

class DialogPage extends StatefulWidget {
  @override
  _DialogPageState createState() => _DialogPageState();
}

class _DialogPageState extends State<DialogPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Dialogs"),
      ),
      body: Center(
        child: SingleChildScrollView(
          padding: EdgeInsets.only(top: 35),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            verticalDirection: VerticalDirection.down,
            children: <Widget>[
              Button(
                  "DEFAULT DIALOG", DialogCollection().defaultDialog, context),
              //Button("DIALOG WITH ICON - 1", DialogCollection().customDialog_1(context)),
              /* Button("Widget", DialogCollection().defaultDialog(context)),
              Button("Widget", DialogCollection().defaultDialog(context)),
              Button("Widget", DialogCollection().defaultDialog(context)),
              Button("Widget", DialogCollection().defaultDialog(context)),*/
            ],
          ),
        ),
      ),
    );
  }

  Button(String text, Function callback, BuildContext context) {
    return Column(
      children: <Widget>[
        Container(
          width: 230,
          child: RaisedButton(
            onPressed: () {
              callback(context);
            },
            shape: RoundedRectangleBorder(
              borderRadius: new BorderRadius.circular(25.0),
              //side: BorderSide(color: Colors.red)
            ),
            color: Colors.blueGrey,
            padding: EdgeInsets.only(
                top: 12.0, bottom: 12.0, left: 40.0, right: 40.0),
            textColor: Colors.white,
            child: Text(
              text,
              textAlign: TextAlign.center,
              style: TextStyle(
                fontWeight: FontWeight.bold,
                fontSize: 18,
              ),
            ),
          ),
        ),
        Container(
          height: 35,
        )
      ],
    );
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DialogPage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

关于flutter - 在构建期间在将小部件作为参数传递时调用setstate()或markneedsbuild(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61095142/

相关文章:

java - 异常不起作用(不显示 JOptionPane 消息)

dart - 在 Flutter 中按下回车键时始终保持软键盘打开

android - flutter 的google_maps地点在搜索后不显示地点

flutter - 每次我们点击底部导航栏上的页面时,如何防止调用 http 请求?

Flutter bloc 测试——emitsInorder 不发出初始状态

Flutter ToggleButton 类 - Flutter 1.9.1

java - 线程 "main"java.lang.NumberFormatException : For input string: "3291105000" 中的异常

javascript - 当 pub.dev 插件没有 web 支持时,使用 npm packages for flutter web

c++ - 我应该为 C 函数 noexcept 声明包装器吗?

dart - 我如何每秒都能让Dart做些事情?