اجرای متد بعد از ساخت کامل ویجت در فلاتر

تا حالا شده دلتون بخواد دقیقاً بعد از اینکه متد build توی یک statefulWidget صدا زده شد، یک snackbar نشون بدین یا مثلا یه دیالوگ به محض نمایش اولین لایه از یک ویجت نشون بدین؟


وقتی خواستم یه اسنکبار (SnackBar) ساده رو توی initState درست کنم یه جورایی nullPointerException گرفتم :D

class HomeScreen extends StatefulWidget {
  @override
  HomeScreenState createState() => new HomeScreenState();
}

class HomeScreenState extends State<HomeScreen> {
  GlobalKey<ScaffoldState> _key = new GlobalKey();

  @override
  void initState() {
    super.initState();
    // NOTE: Calling this function here would crash the app.
    showHelloWorld();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(key: _key, body: Container(color: Colors.red));
  }

  void showHelloWorld() {
    _key.currentState.showSnackBar(SnackBar(
      content: Text(&quotHelloWorld&quot),
    ));
  }
}

اروری که میگیرفتم این بود که یعنی هنوز ویجت رو نساختم و تو میخوای به اون ویجت دسترسی پیدا کنی و یه متد از currentState اون ویجت صدا بزنی؟

و اما واسه اینکه از این حدسم مطمئن بشم (چرا واقعا؟ نمیدونم) رفتم و داخل initState بجای اینکه showHelloWorld رو یهویی صدا بزنم با یه تاخیر کمی مثلا 5 ثانیه صداش میزنم که مطمئن باشم ویجتم ساخته شده ولی خب مسلماً این روش جالبی نیست :)

// Add this after super.initState();
Future.delayed(Duration(seconds: 5)).then((v) => showHelloWorld());

به قول بهتاش "من دیگه رد دادم" و رفتم سراغ دکتر گوگل عزیز و نتایج جالب بود :

  1. بعد از super.initState بیایم و از WidgetsBinding به شکل زیر استفاده کنیم.
    توی داکیومنت فلاتر از WidgetsBinding به عنوان چسب بین لایه ویجت ها و موتور فلاتر نام برده شده. (The glue between the widgets layer and the Flutter engine)
  2. و یا همین تیکه کد رو در قالب یه mixin به ویجت stateful خودتون اضافه کنید.
// Add this after super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => showHelloWorld(context));
از متد addPostFrameCallback برای اضافه کردن یک FrameCallback به انتهای فریم درحال اجرا استفاده میشه به این معنی که به محض اینکه فریم مربوط به رندر اولین لایه از این ویجت تموم بشه متد مورد نظر شما قابل اجراست و میتونه به المنت های رندر شده دسترسی داشته باشه (تکنیکالی).

OR

// Use this Mixin with your StatefulWidget
mixin WidgetLoadMixin<T extends StatefulWidget> on State<T> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) => (context));
  }

  void (BuildContext context);
}

حالا کافیه متد رو override کنید و به راحتی هر کاری که میخواین بعد از لود شدن کامل ویجت انجام بشه توش بنویسید.

*** یه dependency هم هست که همین کار (mixin بالا) رو براتون انجام میده به اسم after layout که میتونید ازش استفاده کنید اما کدهای بالا کارتون رو راه میندازه.


امیدوارم از خوندن این مطلب لذت برده باشید.
مهدی باقری