Flutter: เรียกใช้ method บน Widget build complete


137

ฉันต้องการเรียกใช้ฟังก์ชันเมื่อวิดเจ็ตสร้าง / โหลดเสร็จแล้ว แต่ฉันไม่แน่ใจว่าจะทำอย่างไร กรณีการใช้งานปัจจุบันของฉันคือการตรวจสอบว่าผู้ใช้ได้รับการพิสูจน์ตัวตนหรือไม่และถ้าไม่ให้เปลี่ยนเส้นทางไปยังมุมมองการเข้าสู่ระบบ ฉันไม่ต้องการตรวจสอบก่อนและดันทั้งมุมมองการเข้าสู่ระบบหรือมุมมองหลักซึ่งจะต้องเกิดขึ้นหลังจากที่โหลดมุมมองหลักแล้ว มีอะไรที่ฉันสามารถใช้เพื่อทำสิ่งนี้ได้หรือไม่?


buildก็ไม่น่าที่คุณต้องการเริ่มต้นการเข้าสู่ระบบใน สามารถเรียก Build ได้ทุกเมื่อหลายครั้ง
GünterZöchbauer

คำตอบ:


196

คุณสามารถใช้

https://github.com/slightfoot/flutter_after_layout

ซึ่งเรียกใช้ฟังก์ชันเพียงครั้งเดียวหลังจากการจัดวางเสร็จสมบูรณ์ หรือเพียงแค่ดูการใช้งานและเพิ่มลงในโค้ดของคุณ :-)

ซึ่งโดยพื้นฐานแล้ว

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

ขอบคุณ @thomas ans ของคุณมีประโยชน์มากสำหรับฉัน ฉันทำงานนี้ก่อนสองวันและตอนนี้พวกเขาและหลังจากอ่าน ans ของคุณ ขอบคุณอีกครั้งที่ทำได้ดีมาก
Ravindra Bhanderi

8
ดูคำตอบของ @ anmol.majhail: WidgetsBinding.instance.addPostFrameCallback((_) => yourFunciton(context));ไม่ทำงานอีกต่อไป
Pablo Insua

สวัสดี @ โทมัสมันไม่ได้ผลสำหรับฉัน ยังคงได้รับข้อยกเว้นว่าง มีความคิดอย่างไร
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
Oliver Dixon

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

Flutter 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.idle ... สิ่งที่ใช้งานได้จริงคือการเพิ่มการตรวจสอบภายใน build ()
Alessio

11

หากคุณกำลังมองหาสิ่งที่componentDidMountเทียบเท่าของ ReactNative Flutter ก็มี มันไม่ง่ายอย่างนั้น แต่มันทำงานในลักษณะเดียวกัน ใน Flutter Widgetไม่ได้จัดการกับเหตุการณ์ของพวกเขาโดยตรง แต่พวกเขาใช้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วัตถุได้เช่นเดียวกับ a StatelessWidgetแต่ฉันไม่แนะนำอย่างยิ่ง ฉันยังไม่พบปัญหาใด ๆ แต่โปรดลองใช้ทุกอย่างภายในStateวัตถุก่อน
jerinho.com

2
flutter.dev/docs/cookbook/networking/fetch-data Google ขอแนะนำให้โทรเรียกข้อมูลบน initState () ดังนั้นจึงไม่มีปัญหากับการแก้ปัญหานี้อันที่จริงนี่ควรเป็นคำตอบที่ยอมรับได้
พัฒนา

ใน React Native data ดึงข้อมูลสามารถทำได้componentWillMountก่อนการแสดงเค้าโครง Flutter ให้วิธีแก้ปัญหาที่ง่ายกว่า initStateก็เพียงพอแล้วสำหรับการดึงข้อมูลและการแสดงเค้าโครงหากเรารู้วิธีทำอย่างถูกต้อง
jerinho.com

1
componentWillMount จะเลิกใช้งานเร็ว ๆ นี้ ดังนั้นการดึงข้อมูลจะดำเนินการหลังจากติดตั้งและสร้างส่วนประกอบแล้ว
พัฒนา

10

ใน Flutter เวอร์ชัน 1.14.6, Dart เวอร์ชัน 28

ด้านล่างนี้คือสิ่งที่ใช้ได้ผลสำหรับฉันคุณเพียงแค่ต้องรวมทุกสิ่งที่คุณต้องการให้เกิดขึ้นหลังจากวิธีการสร้างเป็นวิธีการหรือฟังก์ชันแยกต่างหาก

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

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

}

5

วิธีที่ดีที่สุดในการทำเช่นนี้

1. WidgetsBinding

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

2. WidgetsBinding

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

หากคุณต้องการทำสิ่งนี้เพียงครั้งเดียวให้ทำเพราะกรอบงานจะเรียกinitState()method เพียงครั้งเดียวสำหรับวัตถุ State แต่ละชิ้นที่สร้างขึ้น

 @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");
  }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.