8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Flutter] DialogからChangeNotifierの状態にアクセスする

Posted at

今回作成したもの

簡単そうに見えて結構手間取ったのでやり方を記録する。

何が面倒か

Dialogは、showDialog呼び出し元のWidgetではなくRootに追加されるため、ChangeNotifierProvider以下のWidgetでshowDialogを呼び出したとしてもChangeNotifierの状態にはアクセスできない。

Dialog表示時のWidgetTreeイメージ
# なんとなくの期待(間違い)
MaterialApp
  ┗━ ChangeNotifierProvider
       ┗━ Home
            ┗━ Dialog

# 実際
MaterialApp
  ┣━ ChangeNotifierProvider
  ┃   ┗━ Home
  ┃
  ┗━ Dialog          

MaterialAppChangeNotifierProviderでラップしてしまうという方法でもできると思います。アプリの設定など、すべての画面で参照する可能性のある状態はそのほうがいいかも。

どうするか

ChangeNotifierProvider.valueを使います。

ドキュメントの和訳
すでにChangeNotifierのインスタンスがあり、それを公開したい場合は、デフォルトのコンストラクターの代わりにChangeNotifierProvider.valueを使用する必要があります。

コード例(home.dart)
  void _showProgressView(BuildContext context) {
    // ChangeNotifer継承クラスを呼び出す
    final DownloadModel model =
        Provider.of<DownloadModel>(context, listen: false);

    showGeneralDialog<void>(
      ~~
      pageBuilder: (BuildContext context, Animation<void> animation,
          Animation<void> secondaryAnimation) {
        return ChangeNotifierProvider.value(
          value: model,  // <= ここでそれを渡す
          child: ProgressDialog(), // <= この中で使えるようになる
        );
      },
    );
  }
progress_dialog.dart
class ProgressDialog extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 状態を取ってくる
    final double progress = context.watch<DownloadModel>().progress;

    return AlertDialog(
      backgroundColor: Colors.transparent,
      elevation: 0,
      content: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.spaceBetween,

          // 状態(progress)を使って描画を変える
          children: [
            CircularProgressIndicator(value: progress),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 16),
              child: LinearProgressIndicator(value: progress),
            ),
            Text(
              '${(progress * 100).toStringAsFixed(1)}%',
              style: Theme.of(context)
                  .textTheme
                  .headline4
                  .copyWith(color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}

アンチパターン

上記のドキュメントにも記載がありますが、以下のような書き方はNG

NGパターン

// DON'T use ChangeNotifierProvider.value to create your ChangeNotifier.
ChangeNotifierProvider.value(
  value: new MyChangeNotifier(),
  child: ...
)

// DON'T create your ChangeNotifier from variables that can change over the time.
int count;

ChangeNotifierProvider(
  create: (_) => new MyChangeNotifier(count),
  child: ...
)

// DON'T reuse an existing ChangeNotifier using the default constructor
MyChangeNotifier variable;

ChangeNotifierProvider(
  create: (_) => variable,
  child: ...
)

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?