Флаттер: Запуск методу збірки віджетів завершено


137

Я хотів би мати можливість запускати функції, коли віджет закінчить створення / завантаження, але я не впевнений, як. Моїм поточним випадком використання є перевірка автентичності користувача, а якщо ні - перенаправлення на режим входу в систему. Я не хочу перевіряти раніше і натискати ні подання для входу, ні головне представлення, це має відбутися після завантаження основного подання. Чи можу я щось зробити для цього?


Навряд чи ви хочете почати процес входу в систему build. Будувати можна в будь-який час кілька разів.
Гюнтер Цехбауер,

Відповіді:


196

Ви могли б використовувати

https://github.com/slightfoot/flutter_after_layout

який виконує функцію лише один раз після завершення макета. Або просто подивіться на його реалізацію та додайте до свого коду :-)

Що в основному

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

Дякую @thomas, ваш анс мені дуже допомагає. Я працюю над цим до двох днів, а тепер вони і після прочитання ваших відповідей. ще раз спасибі дуже гарна робота
Равіндра Бхандері,

8
Дивіться @ anmol.majhail відповідь: WidgetsBinding.instance.addPostFrameCallback((_) => yourFunciton(context));більше не працює
Пабло Інсуа

Привіт @Thomas, у мене це не працює. все-таки отримати нульовий виняток. будь-яка ідея?
zukijuki

1
@anunixercoder: це залежить від вашого випадку використання. Іноді вам слід зателефонувати іншим способом initState, ніж , наприклад,. в build.
Giraldi

2
вам слід зателефонувати setStateв рамках yourFunctionметоду, щоб він працював
Парс,

92

ОНОВЛЕННЯ: Flutter v1.8.4

Обидва згадані коди працюють зараз:

Робоча:

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

Працює

import 'package:flutter/scheduler.dart';

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

1
Другий вже не працює. NoSuchMethodError (NoSuchMethodError: The method 'addPostFrameCallback' was called on null. Receiver: null
Олівер Діксон,

1
@EliaWeiss - це залежить від вашого варіанту використання - Це лише спосіб викликати функцію на віджетах після збірки. типовим використанням буде init ()
anmol.majhail

22

Є 3 можливі способи:

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

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

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

Що стосується context, він мені знадобився для використання Scaffold.of(context)після того, як були відтворені всі мої віджети.

Але на мою скромну думку, найкращий спосіб це зробити:

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

14

Флаттер 1,2 - дротик 2,2

Відповідно до офіційних вказівок та джерел, якщо ви хочете бути впевненими, що також був намальований останній кадр вашого макета, ви можете написати, наприклад:

import 'package:flutter/scheduler.dart';

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

Для мене це не спрацювало, оскільки під час initState () я отримую SchedulerPhase зі значенням SchedulerPhase.idle ... те, що насправді спрацювало, це додати цю перевірку в build ()
Алессіо,

11

Якщо ви шукаєте componentDidMountеквівалент ReactNative, у Flutter він є. Це не так просто, але працює точно так само. У Flutter Widgets не обробляють свої події безпосередньо. Натомість вони використовують для цього свій Stateоб’єкт.

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.initStateнегайно буде викликано, як тільки екран закінчить візуалізацію макета. І ніколи більше не буде викликаний навіть при гарячому перезавантаженні, якщо ви перебуваєте в режимі налагодження, поки явно не вистачить часу для цього.


З мого прикладу, ви можете використовувати StatefulWidgetклас для обробки його Stateоб'єкта так само, як, StatelessWidgetале я настійно не рекомендую його. Я ще не знайшов жодної проблеми, але, будь ласка, спробуйте спочатку реалізувати все усередині Stateоб’єкта
jerinho.com,

2
flutter.dev/docs/cookbook/networking/fetch-data Google рекомендує викликати отримання даних на initState (). Тому з цим рішенням не виникає жодної проблеми, насправді це повинна бути прийнята відповідь.
Розробник

У React Native отримання даних може здійснюватися componentWillMountбезпосередньо перед візуалізацією макета. Flutter забезпечує більш просте рішення. initStateдостатньо як для отримання даних, так і для візуалізації макета, якщо ми знаємо, як це правильно робити
jerinho.com

1
Незабаром компонентWillMount буде застарілим. Тому отримання буде здійснюватися після монтажу та побудови компонента.
Розробник

10

У версії 1.14.6, версія Dart 28.

Нижче наведено, що у мене вийшло, Вам просто потрібно об’єднати все, що ви хочете, щоб сталося після методу побудови, в окремий метод або функцію.

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

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

}

5

Найкращі способи зробити це,

1. Прив’язка віджетів

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

2. Прив’язка віджетів

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

Його можна викликати всередині initState, обидва будуть викликані лише один раз після побудови віджетів, виконаних з рендерингом.

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

обидва вищезазначені коди працюватимуть однаково, оскільки обидва використовують подібну структуру прив'язки. Для різниці знайдіть посилання нижче.

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



0

Якщо ви хочете зробити це лише один раз, зробіть це, тому що Framework буде викликати initState()метод рівно один раз для кожного об'єкта стану, який він створює.

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

Якщо ви хочете робити це знову і знову, як на зворотному боці або перейти до наступного екрана та ін ..., тоді зробіть це, оскільки didChangeDependencies()викликається, коли змінюється залежність цього стану.

Наприклад, якщо попередній виклик buildпосилався на InheritedWidgetякий пізніше змінився, фреймворк викликав би цей метод, щоб повідомити цей об'єкт про зміну.

Цей метод також називається відразу після initState. З BuildContext.dependOnInheritedWidgetOfExactTypeцього методу можна дзвонити безпечно .

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

Це ваша функція зворотного дзвінка

executeAfterBuildComplete([BuildContext context]){
    print("Build Process Complete");
  }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.