🪣

バケツリレーが役に立つこともある🪣

2024/02/01に公開

tips

ListViewをonTapすると詳細ページに、コンストラクターを使って値を渡す処理を書くことはよくある例ですが、詳細ページから他のページに値を渡す方法が思いつかなかった🫠

最近知った方法だとこんなのがある

  1. riverpodの.familyを使う.
  2. overrideWithValueを使う.

でもこの方法だと思いつかなかった???
実はすごく単純な方法で値を渡すことはできた。渡せばいいだけだから。

これが詳細ページだとする。ここにはTabBarが設置してあります。今回値を渡したいページはStopWatchPageクラスです。こちらのクラスに引数が必須のコンストラクターを作りましょう💡

class FeedDetailPage extends HookConsumerWidget {
  const FeedDetailPage({super.key, required this.taskState});

  final TaskState taskState;

  
  Widget build(BuildContext context, WidgetRef ref) {
    final tabController = useTabController(initialLength: 2);

    return Scaffold(
      appBar: AppBar(
        title: const Text('タスク詳細'),
        bottom: TabBar(
          controller: tabController,
          tabs: const [
            Tab(text: '手動入力'),
            Tab(text: 'ストップウォッチ'),
          ],
        ),
      ),
      body: TabBarView(
        controller: tabController,
        children: [
          const ManualInputPage(),
          StopWatchPage(taskState: taskState),
        ],
      ),
    );
  }
}

このようなコードを書くと、詳細ページから値を受け取ることができます。長いコードですいません🙇

class StopWatchPage extends HookConsumerWidget {
  const StopWatchPage({super.key, required this.taskState});

  final TaskState taskState;

  
  Widget build(BuildContext context, WidgetRef ref) {
    final stopWatchState = ref.watch(stopNotifierProvider);
    final stopWatchController = ref.read(stopNotifierProvider.notifier);

    return SafeArea(
      child: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(16),
          child: SingleChildScrollView(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const SizedBox(height: 40),
                Text(
                  'タスク名',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.black.withOpacity(0.6000000238418579),
                    fontSize: 12,
                    fontFamily: 'Roboto',
                    fontWeight: FontWeight.w400,
                    height: 0.11,
                    letterSpacing: 0.40,
                  ),
                ),
                const SizedBox(height: 16),
                Center(
                  child: Text(
                    taskState.taskName,
                    style: const TextStyle(
                      fontSize: 20,
                    ),
                  ),
                ),
                const SizedBox(height: 20),
                Center(
                  child: Text(
                    "${stopWatchState.hours.toString().padLeft(2, '0')}:${stopWatchState.minutes.toString().padLeft(2, '0')}:${stopWatchState.seconds.toString().padLeft(2, '0')}",
                    style: const TextStyle(
                      fontSize: 78,
                      color: Colors.black,
                      fontWeight: FontWeight.w400,
                    ),
                  ),
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Expanded(
                      child: SizedBox(
                        width: 70,
                        height: 70,
                        child: ElevatedButton(
                          style: ElevatedButton.styleFrom(
                            backgroundColor: const Color(0xFFE0E6F2),
                            shape: const CircleBorder(
                              side: BorderSide(color: Colors.transparent),
                            ),
                          ),
                          onPressed: stopWatchState.started
                              ? stopWatchController.stop
                              : stopWatchController.start,
                          child: Text(
                            stopWatchState.started ? '停止' : '開始',
                            style: const TextStyle(
                              color: Colors.indigo,
                            ),
                          ),
                        ),
                      ),
                    ),
                    const SizedBox(width: 8),
                    Expanded(
                      child: SizedBox(
                        width: 70,
                        height: 70,
                        child: ElevatedButton(
                          style: ElevatedButton.styleFrom(
                            backgroundColor: const Color(0xFFE0E6F2),
                            shape: const CircleBorder(
                              side: BorderSide(color: Colors.transparent),
                            ),
                          ),
                          onPressed: () {},
                          child: const Text(
                            '完了',
                            style: TextStyle(
                              color: Colors.indigoAccent,
                            ),
                          ),
                        ),
                      ),
                    ),
                    const SizedBox(width: 8),
                    Expanded(
                      child: SizedBox(
                        width: 70,
                        height: 70,
                        child: ElevatedButton(
                          style: ElevatedButton.styleFrom(
                            backgroundColor: const Color(0xFFE0E6F2),
                            shape: const CircleBorder(
                              side: BorderSide(color: Colors.transparent),
                            ),
                          ),
                          onPressed: stopWatchController.reset,
                          child: const Text(
                            'リセット',
                            style: TextStyle(
                              color: Colors.indigoAccent,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

こんな感じで表示できます:

まとめ

今回は分かり難い記事になってしまいましたが、重要な部分はコンストラクーがあれば、ListViewをonTapして詳細ページへモデルクラスの値を渡して、渡した値を他のページに渡したいときは、引数が必須のコンストラクターをつければ、Reactのpropsみたいに、値を他のページに簡単に渡すことができます。

想定されるユースケースとしては、特定のデータのリストを詳細ページに渡して表示できるけど、他のページにも表示したい場面で使うことができます。

Discussion