Flutter: Uruchom metodę przy kompilacji widżetu


137

Chciałbym móc uruchamiać funkcje po zakończeniu budowania / ładowania widżetu, ale nie jestem pewien, jak to zrobić. Moim obecnym przypadkiem jest sprawdzenie, czy użytkownik jest uwierzytelniony, a jeśli nie, przekierowanie do widoku logowania. Nie chcę sprawdzać wcześniej i naciskać ani widoku logowania, ani widoku głównego, musi to nastąpić po załadowaniu widoku głównego. Czy jest coś, czego mogę użyć, aby to zrobić?


Jest mało prawdopodobne, że chcesz rozpocząć proces logowania w build. Build można wywołać w dowolnym momencie wielokrotnie.
Günter Zöchbauer

Odpowiedzi:


196

Możesz użyć

https://github.com/slightfoot/flutter_after_layout

który wykonuje funkcję tylko raz po ukończeniu układu. Lub po prostu spójrz na jego implementację i dodaj do swojego kodu :-)

Co jest w zasadzie

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

Dzięki @thomas, twoja odpowiedź jest dla mnie bardzo pomocna. Pracuję nad tym przed dwoma dniami, a teraz oni i po przeczytaniu twoich odpowiedzi. jeszcze raz bardzo dziękuję za dobrą robotę
Ravindra Bhanderi

8
Zobacz odpowiedź @ anmol.majhail: WidgetsBinding.instance.addPostFrameCallback((_) => yourFunciton(context));już nie działa
Pablo Insua

Cześć @ Thomas, to nie działa dla mnie. nadal otrzymujesz zerowy wyjątek. dowolny pomysł ?
zukijuki

1
@anunixercoder: to zależy od twojego przypadku użycia. Czasami należy to wywołać w inny sposób niż initStatenp. w build.
Giraldi

2
należy zgłosić setStatew ciągu yourFunctionmetody, aby to działa
Pars

92

AKTUALIZACJA: Flutter v1.8.4

Oba wymienione kody teraz działają:

Pracujący:

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

Pracujący

import 'package:flutter/scheduler.dart';

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

1
Drugi już nie działa. NoSuchMethodError (NoSuchMethodError: The method 'addPostFrameCallback' was called on null. Receiver: null
Oliver Dixon

1
@EliaWeiss - to zależy od twojego przypadku użycia - to tylko sposób na wywołanie funkcji w widżetach po kompilacji. typowe użycie będzie init ()
anmol.majhail

22

Istnieją 3 możliwe sposoby:

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

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

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

A jeśli chodzi o context, potrzebowałem go do użycia Scaffold.of(context)po wyrenderowaniu wszystkich moich widżetów.

Ale moim skromnym zdaniem najlepszym sposobem na to jest:

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

14

Flutter 1.2 - strzałka 2.2

Zgodnie z oficjalnymi wytycznymi i źródłami, jeśli chcesz mieć pewność, że narysowana została również ostatnia klatka Twojego layoutu , możesz napisać np .:

import 'package:flutter/scheduler.dart';

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

Dla mnie to nie zadziałało, ponieważ w czasie initState () otrzymuję SchedulerPhase z wartością SchedulerPhase.idle ... tak naprawdę zadziałało dodanie tego sprawdzenia w build ()
Alessio

11

Jeśli szukasz componentDidMountodpowiednika ReactNative , Flutter go ma. To nie jest takie proste, ale działa w ten sam sposób. We Flutterze Widgets nie obsługują bezpośrednio swoich zdarzeń. Zamiast tego używają Statedo tego celu.

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.initStatezostanie wywołana natychmiast po zakończeniu renderowania układu przez screen. I nigdy więcej nie zostanie wywołany, nawet przy ponownym ładowaniu na gorąco, jeśli jesteś w trybie debugowania, dopóki wyraźnie nie osiągnie czasu, aby to zrobić.


Z mojego przykładu możesz użyć StatefulWidgetklasy do obsługi Stateobiektu tak jak a, StatelessWidgetale zdecydowanie tego nie polecam. Nie znalazłem jeszcze żadnego problemu, ale Statenajpierw spróbuj zaimplementować wszystko wewnątrz obiektu
jerinho.com

2
flutter.dev/docs/cookbook/networking/fetch-data Google zaleca wywołanie pobierania danych w initState (). Dlatego nie ma problemu z tym rozwiązaniem, w rzeczywistości powinna to być akceptowana odpowiedź.
Deweloper

W React Native pobieranie danych może odbywać się componentWillMounttuż przed renderowaniem layoutu. Flutter zapewnia prostsze rozwiązanie. initStatewystarczy zarówno do pobierania danych, jak i renderowania układu, jeśli wiemy, jak to zrobić poprawnie
jerinho.com

1
KomponentWillMount wkrótce zostanie wycofany. Dlatego pobieranie zostanie wykonane po zamontowaniu i skonstruowaniu komponentu.
Deweloper

10

W wersji Flutter 1.14.6, Dart w wersji 28.

Poniżej znajduje się, co zadziałało w moim przypadku. Po prostu musisz spakować wszystko, co chcesz, aby wydarzyło się po metodzie kompilacji, w osobną metodę lub funkcję.

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

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

}

5

Najlepsze sposoby na zrobienie tego,

1. WidgetsBinding

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

2. WidgetsBinding

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

Można go wywołać wewnątrz initState, oba zostaną wywołane tylko raz po zakończeniu renderowania widgetów Build.

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

oba powyższe kody będą działać tak samo, ponieważ oba używają podobnej struktury powiązań. Aby zobaczyć różnicę, znajdź poniższy link.

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


3

Wypróbuj SchedulerBinding,

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

0

Jeśli chcesz to zrobić tylko raz, zrób to, ponieważ Framework wywoła initState()metodę dokładnie raz dla każdego utworzonego obiektu State.

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

Jeśli chcesz to robić raz po raz, jak z tyłu lub przejść do następnego ekranu itp., Zrób to, ponieważ didChangeDependencies()Called, gdy zmienia się zależność tego obiektu State.

Na przykład, jeśli poprzednie wywołanie buildodwoływało się do elementu, InheritedWidgetktóry później się zmienił, struktura wywoła tę metodę, aby powiadomić ten obiekt o zmianie.

Ta metoda jest również wywoływana bezpośrednio po initState. Dzwonienie BuildContext.dependOnInheritedWidgetOfExactTypez tej metody jest bezpieczne .

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

To jest twoja funkcja oddzwaniania

executeAfterBuildComplete([BuildContext context]){
    print("Build Process Complete");
  }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.