Flattern: Führen Sie die Methode für den Widget-Build aus


121

Ich möchte Funktionen ausführen können, sobald ein Widget fertig erstellt / geladen wurde, bin mir aber nicht sicher, wie. Mein aktueller Anwendungsfall besteht darin, zu überprüfen, ob ein Benutzer authentifiziert ist, und wenn nicht, zu einer Anmeldeansicht umzuleiten. Ich möchte nicht vorher überprüfen und entweder die Anmeldeansicht oder die Hauptansicht drücken, es muss geschehen, nachdem die Hauptansicht geladen wurde. Kann ich dazu irgendetwas verwenden?


Es ist unwahrscheinlich, dass Sie den Anmeldevorgang starten möchten build. Build kann jederzeit mehrmals aufgerufen werden.
Günter Zöchbauer

Antworten:


181

Du könntest benutzen

https://github.com/slightfoot/flutter_after_layout

Dies führt eine Funktion nur einmal nach Abschluss des Layouts aus. Oder schauen Sie sich einfach die Implementierung an und fügen Sie sie Ihrem Code hinzu :-)

Welches ist im Grunde

  void initState() {
    super.initState();
    WidgetsBinding.instance
        .addPostFrameCallback((_) => yourFunction(context));
  }

Danke @thomas deine ans ist sehr hilfreich für mich. Ich arbeite vor zwei Tagen daran und jetzt und nach dem Lesen Ihrer Ans.
Nochmals vielen

6
Siehe @ anmol.majhail Antwort: WidgetsBinding.instance.addPostFrameCallback((_) => yourFunciton(context));funktioniert nicht mehr
Pablo Insua

Hallo @Thomas, es funktioniert nicht bei mir. immer noch null Ausnahme bekommen. irgendeine Idee ?
Zukijuki

1
@anunixercoder: Das hängt von Ihrem Anwendungsfall ab. Manchmal sollten Sie es anders nennen als initStatez. in build.
Giraldi

2
Sie sollten setStateinnerhalb der yourFunctionMethode aufrufen , damit es funktioniert
Pars

88

UPDATE: Flutter v1.8.4

Beide genannten Codes funktionieren jetzt:

Arbeiten:

WidgetsBinding.instance
        .addPostFrameCallback((_) => yourFunction(context));

Arbeiten

import 'package:flutter/scheduler.dart';

SchedulerBinding.instance.addPostFrameCallback((_) => yourFunction(context));

1
Der zweite funktioniert nicht mehr. NoSuchMethodError (NoSuchMethodError: The method 'addPostFrameCallback' was called on null. Receiver: null
Oliver Dixon

1
@EliaWeiss - es hängt von Ihrem Anwendungsfall ab - Dies ist nur eine Möglichkeit, eine Funktion für Widgets nach dem Build aufzurufen. typische Verwendung wird in init ()
anmol.majhail

19

Es gibt drei Möglichkeiten:

1) WidgetsBinding.instance.addPostFrameCallback((_) => yourFunc(context));

2) Future.delayed(Duration.zero, () => yourFunc(context));

3) Timer.run(() => yourFunc(context));

Was contextbrauchte ich es für den Einsatz in Scaffold.of(context)nachdem alle meine Widgets gemacht wurden.

Aber meiner bescheidenen Meinung nach ist der beste Weg, dies zu tun:

void main() async {
  WidgetsFlutterBinding.ensureInitialized(); //all widgets are rendered here
  await yourFunc();
  runApp( MyApp() );
}

13

Flattern 1.2 - Pfeil 2.2

Gemäß den offiziellen Richtlinien und Quellen können Sie beispielsweise schreiben, wenn Sie sicher sein möchten, dass auch der letzte Rahmen Ihres Layouts gezeichnet wurde:

import 'package:flutter/scheduler.dart';

void initState() {
   super.initState();
   if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
        SchedulerBinding.instance.addPostFrameCallback((_) => yourFunction(context));
   }
}

Für mich hat das nicht funktioniert, weil ich zur Zeit von initState () schedulerPhase mit dem Wert SchedulerPhase.idle erhalte ... was tatsächlich funktioniert hat, war, diese Prüfung in build () hinzuzufügen
Alessio

11

Wenn Sie nach dem componentDidMountÄquivalent von ReactNative suchen , hat Flutter es. Es ist nicht so einfach, aber es funktioniert genauso. In Flutter behandeln Widgets ihre Ereignisse nicht direkt. Stattdessen verwenden sie ihr StateObjekt, um dies zu tun.

class MyWidget extends StatefulWidget{

  @override
  State<StatefulWidget> createState() => MyState(this);

  Widget build(BuildContext context){...} //build layout here

  void onLoad(BuildContext context){...} //callback when layout build done
}

class MyState extends State<MyWidget>{

  MyWidget widget;

  MyState(this.widget);

  @override
  Widget build(BuildContext context) => widget.build(context);

  @override
  void initState() => widget.onLoad(context);
}

State.initStateWird sofort aufgerufen, sobald der Bildschirm das Rendern des Layouts beendet hat. Und wird auch beim Hot-Reload nie wieder aufgerufen, wenn Sie sich im Debug-Modus befinden, bis die Zeit dafür explizit erreicht ist.


In meinem Beispiel können Sie die StatefulWidgetKlasse verwenden, um das StateObjekt wie ein Objekt zu behandeln, StatelessWidgetaber ich kann es nur empfehlen. Ich habe noch kein Problem gefunden, aber bitte versuchen Sie zuerst, alles innerhalb des StateObjekts zu implementieren
jerinho.com

2
flutter.dev/docs/cookbook/networking/fetch-data Google empfiehlt, das Abrufen von Daten auf initState () aufzurufen. Daher gibt es kein Problem mit dieser Lösung, in der Tat sollte dies die akzeptierte Antwort sein.
Entwickler

In React Native kann das Abrufen von Daten componentWillMountunmittelbar vor dem Rendern des Layouts erfolgen. Flattern bietet eine einfachere Lösung. initStateist sowohl für das Abrufen von Daten als auch für das gerenderte Layout ausreichend, wenn wir wissen, wie es richtig gemacht wird
jerinho.com

1
componentWillMount wird bald veraltet sein. Daher erfolgt das Abrufen, nachdem die Komponente montiert und konstruiert wurde.
Entwickler

7

In Flatter Version 1.14.6, Dart Version 28.

Im Folgenden wird beschrieben, was für mich funktioniert hat: Sie müssen lediglich alles, was nach der Erstellungsmethode geschehen soll, in einer separaten Methode oder Funktion bündeln.

@override
void initState() {
super.initState();
print('hello girl');

WidgetsBinding.instance
    .addPostFrameCallback((_) => afterLayoutWidgetBuild());

}

3

Versuchen Sie SchedulerBinding,

 SchedulerBinding.instance
                .addPostFrameCallback((_) => setState(() {
              isDataFetched = true;
            }));

0

Wenn Sie dies nur einmal tun möchten, tun Sie dies, da das Framework die initState()Methode für jedes von ihm erstellte Statusobjekt genau einmal aufruft.

 @override
  void initState() {
    super.initState();
    WidgetsBinding.instance
        .addPostFrameCallback((_) => executeAfterBuildComplete(context));
  }

Wenn Sie dies immer wieder wie auf der Rückseite tun oder zu einem nächsten Bildschirm usw. navigieren möchten, tun Sie dies, weil Wird didChangeDependencies()aufgerufen, wenn sich eine Abhängigkeit dieses Statusobjekts ändert.

Wenn beispielsweise der vorherige Aufruf auf buildeinen InheritedWidgetspäter geänderten Aufruf verweist , ruft das Framework diese Methode auf, um dieses Objekt über die Änderung zu benachrichtigen.

Diese Methode wird auch unmittelbar danach aufgerufen initState. Es ist sicher, BuildContext.dependOnInheritedWidgetOfExactTypevon dieser Methode aufzurufen .

 @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    WidgetsBinding.instance
        .addPostFrameCallback((_) => executeAfterBuildComplete(context));
  }

Dies ist Ihre Rückruffunktion

executeAfterBuildComplete([BuildContext context]){
    print("Build Process Complete");
  }

0

Beste Möglichkeiten, dies zu tun,

1. WidgetsBinding

WidgetsBinding.instance.addPostFrameCallback((_) {
      print("WidgetsBinding");
    });

2. WidgetsBinding

SchedulerBinding.instance.addPostFrameCallback((_) {
  print("SchedulerBinding");
});

Es kann innerhalb aufgerufen initStatewerden. Beide werden nur einmal aufgerufen, nachdem die Build-Widgets mit dem Rendern fertig sind.

@override
  void initState() {
    // TODO: implement initState
    super.initState();
    print("initState");
    WidgetsBinding.instance.addPostFrameCallback((_) {
      print("WidgetsBinding");
    });
    SchedulerBinding.instance.addPostFrameCallback((_) {
      print("SchedulerBinding");
    });
  }

Beide oben genannten Codes funktionieren genauso, da beide das ähnliche Bindungsframework verwenden. Für den Unterschied finden Sie den folgenden Link.

https://medium.com/flutterworld/flutter-schedulerbinding-vs-widgetsbinding-149c71cb607f

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.