setState () oder markNeedsBuild werden während des Builds aufgerufen

74
class MyHome extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new MyHomePage2();
}

class MyHomePage2 extends State<MyHome> {
  List items = new List();

  buildlist(String s) {
    setState(() {
      print("entered buildlist" + s);
      List refresh = new List();
      if (s == 'button0') {
        refresh = [
          new Refreshments("Watermelon", 250),
          new Refreshments("Orange", 275),
          new Refreshments("Pine", 300),
          new Refreshments("Papaya", 225),
          new Refreshments("Apple", 250),
        ];
      } else if (s == 'button1') {
        refresh = [
          new Refreshments("Pina Colada", 250),
          new Refreshments("Bloody Mary", 275),
          new Refreshments("Long Island Ice tea", 300),
          new Refreshments("Screwdriver", 225),
          new Refreshments("Fusion Cocktail", 250),
        ];
      } else if (s == 'button2') {
        refresh = [
          new Refreshments("Virgin Pina Colada", 250),
          new Refreshments("Virgin Mary", 275),
          new Refreshments("Strawberry Flush", 300),
          new Refreshments("Mango Diver", 225),
          new Refreshments("Peach Delight", 250),
        ];
      } else {
        refresh = [
          new Refreshments("Absolute", 250),
          new Refreshments("Smirnoff", 275),
          new Refreshments("White Mischief", 300),
          new Refreshments("Romanov", 225),
          new Refreshments("Blender's Pride", 250),
        ];
      }

      for (var item in refresh) {
        items.add(new ItemsList(item));
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    var abc = MediaQuery.of(context).size;

    print(abc.width);

    var width = abc.width / 4;

    Text text = new Text("Dev");
    Text text2 = new Text("Sneha");
    Text text3 = new Text("Prashant");
    Text text4 = new Text("Vikesh");

    var pad = const EdgeInsets.all(10.0);

    Padding pad1 = new Padding(child: text, padding: pad);
    Padding pad2 = new Padding(child: text2, padding: pad);
    Padding pad3 = new Padding(child: text3, padding: pad);
    Padding pad4 = new Padding(child: text4, padding: pad);

    ListView listView = new ListView(children: <Widget>[
      new Image.asset('images/party.jpg'),
      pad1,
      pad2,
      pad3,
      pad4
    ]);

    Drawer drawer = new Drawer(child: listView);

    return new Scaffold(
      drawer: drawer,

      appBar: new AppBar(
        title: new Text('Booze Up'),
      ),
      body: new Column(children: <Widget>[
        new ListView.builder(
          scrollDirection: Axis.horizontal,
          itemCount: 4,
          itemBuilder: (BuildContext context, int index) {
            return new Column(children: <Widget>[
              new Container(
                child: new Flexible(
                    child: new FlatButton(
                  child: new Image.asset('images/party.jpg',
                      width: width, height: width),
                  onPressed: buildlist('button' + index.toString()),
                )),
                width: width,
                height: width,
              )
            ]);
          },
        ),
        new Expanded(
            child: new ListView(
          padding: new EdgeInsets.fromLTRB(10.0, 10.0, 0.0, 10.0),
          children: items,
          scrollDirection: Axis.vertical,
        )),
      ]),

      floatingActionButton: new FloatingActionButton(
        onPressed: null,
        child: new Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class Refreshments {
  String name;
  int price;

  Refreshments(this.name, this.price);
}

class ItemsList extends StatelessWidget {
  final Refreshments refreshments;

  ItemsList(this.refreshments);

  @override
  Widget build(BuildContext context) {
    return new ListTile(
      onTap: null,
      title: new Text(refreshments.name),
    );
  }
}

Formatiert von DartPad ;-)

Ich habe zwei Fehler:

1] Das horizontale Ansichtsfenster erhielt eine unbegrenzte Höhe. Einem horizontalen Ansichtsfenster wurde ein unbegrenzter vertikaler Raum zum Erweitern eingeräumt.

2] setState () oder markNeedsBuild, die während des Builds aufgerufen wurden Ein vertikaler Renderflex, der um 99488 Pixel übergelaufen ist.

Bitte helfen Sie mir dabei. Ich erstelle diese App, bei der auf jedem Bild eine Liste unten angezeigt wird. Die Bilder befinden sich in einer Reihe und die Liste sollte unter der Reihe angezeigt werden.

Vielen Dank.

Divyang Shah
quelle

Antworten:

-21

Ich habe neu erstellt, was Sie versuchen, mit nur zwei Ihrer Erfrischungselemente möchten Sie wahrscheinlich Dinge umgestalten und das Layout besser handhaben, aber der Einfachheit halber versuchen Sie, diesem Beispiel zu folgen und es mit dem zu vergleichen Sie versuchen zu erreichen:

Geben Sie hier die Bildbeschreibung ein

import "package:flutter/material.dart";

class LetsParty extends StatefulWidget {
  @override
  _LetsPartyState createState() => new _LetsPartyState();
}

class _LetsPartyState extends State<LetsParty> {
  Image _partyImage = new Image.network(
      "http://www.freshcardsgifts.co.uk/images/_lib/animal-party-greetings-card-3003237-0-1344698261000.jpg");

  final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();

  List<List> list = [
    ["Pina Colada",
    "Bloody Mary",
    "Strawberry Flush",
    "Mango Diver",
    "Peach Delight"
    ],
    [
      "Absolute",
      "Smirnoff",
      "White Mischief",
      "Romanov",
      "Blender's Pride"
    ]
  ];

  List<String> visibleList = null;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: scaffoldKey,
      appBar: new AppBar(title: new Text("Let's Party"),),
      body: new ListView(
        // shrinkWrap: true,
        children: <Widget>[


          new Container (
              height: 150.0,
              child: new ListView.builder(
                  shrinkWrap: true,
                  scrollDirection: Axis.horizontal,
                  itemCount: 2, //add the length of your list here
                  itemBuilder: (BuildContext context, int index) {
                    return new Column(
                      children: <Widget>[

                        ///Flexible let's your widget flex in  the given space, dealing with the overflow you have
                        //  new Flexible(child: new FlatButton(onPressed: ()=>print("You pressed Image No.$index"), child: _partyImage)),
                        new Flexible (child: new Container(
                            child: new FlatButton(onPressed: () {
                              scaffoldKey.currentState.showSnackBar(
                                  new SnackBar(
                                      content: new Text(
                                          "You pressed Image No.$index")));

                              setState(() {
                                visibleList = list[index];
                              });
                            },
                                child: _partyImage),
                            width: 100.0,
                            height: 100.0
                        ),),
                        //Exact width and height, consider adding Flexible as a parent to the Container
                        new Text("Text$index"),
                      ],
                    );
                  })),

          new Column(children: visibleList==null?new List():new List.generate(5, (int i) {
            new ListTile(title: new Text(visibleList[i]),
              onTap: () =>
                  scaffoldKey.currentState.showSnackBar(new SnackBar(
                    content: new Text("Your choise is ${visibleList[i]}"),)),
            );
          }))
        ],),);
  }
}
Aziza
quelle
83
Dies sollte nicht die gewählte Antwort sein. Alles, was es tut, ist, den OP-Code neu zu schreiben, um die Fehler zu beheben, ohne darauf einzugehen, was sie waren oder warum sie passiert sind. Daher ist es nicht hilfreich, wenn andere Personen mit denselben oder ähnlichen Fehlern auf diese Seite kommen.
Abion47
2
@ Abion47 buchstäblich sind die meisten Flatterantworten nur Code ohne Erklärung
Peter Haddad
152

In meinem Fall habe ich die setState-Methode aufgerufen, bevor die Build-Methode den Prozess zum Erstellen von Widgets abgeschlossen hat.

Dieser Fehler kann auftreten, wenn Sie vor Abschluss der Erstellungsmethode und in vielen anderen Fällen eine Snackleiste oder einen Warndialog anzeigen. Verwenden Sie in einer solchen Situation die folgende Rückruffunktion.

WidgetsBinding.instance.addPostFrameCallback((_){

  // Add Your Code here.

});

oder Sie können auch SchedulerBinding verwenden, das dasselbe tut.

SchedulerBinding.instance.addPostFrameCallback((_) {

  // add your code here.

  Navigator.push(
        context,
        new MaterialPageRoute(
            builder: (context) => NextPage()));
});
Entwickeln
quelle
25
thaaaaaaaaaaaaaaaaaaanks maaan
Richard Willian
9
Dies sollte die akzeptierte Antwort sein. Dieser Fehler ist mir beim Erstellen eines neuen MaterialPageRoutein einem FutureBuilder(Anmeldeerfolgsbildschirm) aufgetreten .
Phani Rithvij
Vielen Dank an @Developine für diese Lösung. Ich habe den ersten Teil Ihrer Lösungen verwendet.
Nilesh
Das funktioniert, danke! Ich hatte das gleiche Problem beim Aufruf von Navigator.of(context).popUntilmethod
damato
Vielen Dank
N Sivaram
126

Dein Code

onPressed: buildlist('button'+index.toString()),

führt buildlist()das Ergebnis aus und übergibt es an onPressed, aber das ist nicht das gewünschte Verhalten.

Es sollte sein

onPressed: () => buildlist('button'+index.toString()),

Auf diese Weise wird eine Funktion (Schließung) übergeben onPressed, die bei Ausführung aufgerufen wirdbuildlist()

Günter Zöchbauer
quelle
Ich erhalte immer noch den Fehler: Das horizontale Ansichtsfenster erhielt eine unbegrenzte Höhe. Was bedeutet das ?
Divyang Shah
Ich denke, ich muss das @Darky oder jemand anderem überlassen.
Günter Zöchbauer
1
@DivyangShah Wenn Sie einen Container als übergeordnetes Element von Flexible verwenden, sollte es umgekehrt sein.
Aziza
1
Ich liebe das, habe es gerade für 3 Stunden überarbeitet und diese Fehlerzeile bekommen. Du hast es für mich behoben, jetzt funktioniert alles gut!
Julian Otto
16

Ich habe den Status auch während des Builds festgelegt, also habe ich ihn auf das nächste Häkchen verschoben und es hat funktioniert.

vorher

myFunction()

Neu

Future.delayed(Duration.zero, () async {
  myFunction();
});
Alfiepoleon
quelle
1
Danke, das funktioniert für mich. In meinem Fall mache ich Infinite Gridview und ich habe versucht, die Ladeansicht unten anzuzeigen und onBuild hat zu oft aufgerufen. Aber ich arbeite mit dieser Lösung. Nochmals vielen Dank.
Tejas Trivedi
1
Es hat auch bei mir funktioniert. Vielen Dank!
Blen
1
Es hat auch bei mir funktioniert. Gut gemacht!
Boris
Einfachste Lösung, danke!
Atereshkov
1

Ich habe diesen Fehler aufgrund eines ziemlich dummen Fehlers erhalten, aber vielleicht ist jemand hier, weil er genau das Gleiche getan hat ...

In meinem Code habe ich zwei Klassen. Eine Klasse (B) ist nur da, um mir ein spezielles Widget mit einer onTap-Funktion zu erstellen. Die Funktion, die durch das Tippen des Benutzers ausgelöst werden sollte, befand sich in der anderen Klasse (A). Also habe ich versucht, die Funktion der Klasse A an den Konstruktor der Klasse B zu übergeben, damit ich sie dem onTap zuweisen kann.

Leider habe ich die Funktionen, anstatt sie zu übergeben, aufgerufen. So sah es aus:

ClassB classBInstance = ClassB(...,myFunction());

Offensichtlich ist dies der richtige Weg:

ClassB classBInstance = classB(...,myFunction);

Dies löste meine Fehlermeldung. Der Fehler ist sinnvoll, da myFunction die Instanz der Klasse B ausführen musste und mein Build daher zuerst abgeschlossen werden musste (beim Aufrufen meiner Funktion wird eine Snackbar angezeigt).

Hoffe das hilft jemandem eines Tages!

Eric Pleines
quelle
:) haahaha für die erste Zeile
Divyang Shah
0

Das Problem dabei WidgetsBinding.instance.addPostFrameCallbackist, dass es keine umfassende Lösung ist.

Gemäß dem Vertrag von addPostFrameCallback -

Planen Sie einen Rückruf für das Ende dieses Frames. [...] Dieser Rückruf wird während eines Frames ausgeführt, unmittelbar nach den [...] dauerhaften Frame-Rückrufen. Wenn ein Frame ausgeführt wird und Post-Frame-Rückrufe noch nicht ausgeführt wurden, wird der registrierte Rückruf weiterhin während des Frames ausgeführt. Andernfalls wird der registrierte Rückruf im nächsten Frame ausgeführt.

Diese letzte Zeile klingt für mich wie ein Deal-Breaker.

Diese Methode ist nicht für den Fall geeignet, dass kein "aktueller Rahmen" vorhanden ist und der Flattermotor im Leerlauf läuft. Natürlich, in diesem Fall kann man aufrufen setState()direkt, aber auch hier, dass nicht wird immer Arbeit - manchmal gibt es einfach ist ein aktueller Rahmen.


Zum Glück SchedulerBindinggibt es auch eine Lösung für diese kleine Warze - SchedulerPhase

Bauen wir eine bessere setState, die sich nicht beschwert.

( endOfFramemacht im Grunde das Gleiche wie addPostFrameCallback, außer dass es versucht, einen neuen Frame zu planen SchedulerPhase.idle, und es verwendet async-await anstelle von Rückrufen)

Future<bool> rebuild() async {
  if (!mounted) return false;

  // if there's a current frame,
  if (SchedulerBinding.instance.schedulerPhase != SchedulerPhase.idle) {
    // wait for the end of that frame.
    await SchedulerBinding.instance.endOfFrame;
    if (!mounted) return false;
  }

  setState(() {});
  return true;
}

Dies sorgt auch für schönere Kontrollflüsse, die offen gesagt einfach funktionieren .

await someTask();

if (!await rebuild()) return;

await someOtherTask();
Dev Aggarwal
quelle