1. ホーム
  2. dart

[解決済み] Flutter initState メソッドでコンテキストを取得する

2022-07-23 03:57:09

質問

私は initState がこのための正しい関数であるかどうかはわかりません。 私が実現しようとしているのは、ページがレンダリングされたときにいくつかのチェックを実行し、それらに基づいて AlertDialog を開き、必要であれば設定を行うことです。

あるページがあり、そのページには状態があります。 それは initState 関数は次のようになります。

@override
void initState() {
    super.initState();
    if (!_checkConfiguration()) {
        _showConfiguration(context);
    }
}

_showConfiguration をこのように

void _showConfiguration(BuildContext context) {
    AlertDialog dialog = new AlertDialog(
        content: new Column(
            children: <Widget>[
                new Text('@todo')
            ],
        ),
        actions: <Widget>[
            new FlatButton(onPressed: (){
                Navigator.pop(context);
            }, child: new Text('OK')),
        ],
    );

    showDialog(context: context, child: dialog);
}

このチェックを行い、必要に応じてモーダルを呼び出すためのより良い方法があれば、適切な方向性を示してください。 onState または onRender 関数に割り当てることができるコールバック、または build 関数に割り当てることができますが、見つけることができませんでした。


編集: こちらでも同じような問題があったようです。 Flutter initStateでページへのリダイレクトを行う

どのように解決するのですか?

メンバ変数のコンテキストにアクセスできるのは initState でアクセスできますが、すべてに使えるわけではありません。これは initState のドキュメントからです。

を使うことはできません。 [BuildContext.inheritFromWidgetOfExactType] を使うことはできません。 メソッドを使用することはできません。しかし [didChangeDependencies] はこのメソッドの直後に呼び出されます。 はこのメソッドの直後に呼び出され [BuildContext.inheritFromWidgetOfExactType] はそこで使うことができます。

初期化ロジックを didChangeDependencies に移動させることもできますが、それは必ずしもあなたの望むところではないかもしれません。 didChangeDependencies はウィジェットのライフサイクルの中で何度も呼び出される可能性があるからです。

代わりに、ウィジェットが初期化された後まで呼び出しを委ねる非同期呼び出しを行う場合、意図したとおりにコンテキストを使用することができます。

これを行う簡単な方法は、futureを使用することです。

Future.delayed(Duration.zero,() {
  ... showDialog(context, ....)
}

もう一つの方法は、より「正しい」かもしれませんが、flutterのスケジューラを使ってフレーム後のコールバックを追加することです。

SchedulerBinding.instance.addPostFrameCallback((_) {
  ... showDialog(context, ....)
});

そして最後に、initState関数で非同期呼び出しを使うために、私が好きな小技を紹介します。

() async {
  await Future.delayed(Duration.zero);
  ... showDialog(context, ...)      
}();

以下は、単純なFuture.delayedを使った完全な例です。

import 'dart:async';

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  bool _checkConfiguration() => true;

  void initState() {
    super.initState();
    if (_checkConfiguration()) {
      Future.delayed(Duration.zero,() {
        showDialog(context: context, builder: (context) => AlertDialog(
          content: Column(
            children: <Widget>[
              Text('@todo')
            ],
          ),
          actions: <Widget>[
            FlatButton(onPressed: (){
              Navigator.pop(context);
            }, child: Text('OK')),
          ],
        ));
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
    );
  }
}


コメントで提供された OP からのより多くのコンテキストにより、彼らの特定の問題に対する少し良い解決策を提供することができます。アプリによっては、アプリを初めて開いたかどうかに応じて、表示するページを決定する必要があります(例: set home を異なるものに設定します。また、ダイアログはモバイルでは必ずしも最適な UI 要素ではありません。追加する必要のある設定と次のボタンを含む完全なページを表示する方がよい場合があります。