Onishi take on issue

備忘録と好き勝手言います

初心者と一緒にFlutterを学ぼう はじめてのアプリを改良しよう

ワールドカップの見すぎでflutterを怠っておりましたのでワールドカップも見つつ頑張ります。

前のパートでルーレットのアプリを簡単に作りました。
今回はいろいろ改良を加えてみようかなのパートとなります

ルーレットの中身を自分で入力しよう

今までAさん~Hさんで分けてきましたが、これを自分で入力できるようにします

とりあえず書いてみる

main.dart

import 'package:flutter/material.dart';
import 'package:myapp1/screens/roulette.dart';
import 'package:myapp1/screens/home.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      routes: {
        HomePage.routeName: (context) => HomePage(),
        RouletteApp.routeName: (context) => RouletteApp(),
      },
      initialRoute: HomePage.routeName,
    ); //ルーティング設定です(testing_appを参考にしてます)
  }
}

RoulettePageというクラスを消したので後述のRouletteAppに変更しています。
他は変化ありません

home.dart

import 'package:flutter/material.dart';
import 'package:myapp1/screens/roulette.dart';

class HomePage extends StatelessWidget {
  static const routeName = '/';
  HomePage({super.key});

  final oneController = TextEditingController();
  final twoController = TextEditingController();
  final threeController = TextEditingController();

//テキストフォームのためのコントローラーを設置しておきます。

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Testing Sample'),
      ),
      body: Container(
        child: Column(
          children: [
            TextField(
                controller: oneController,
                decoration: InputDecoration(
                  hintText: '1つめ',
                )
            ),
            TextField(
                controller: twoController,
                decoration: InputDecoration(
                  hintText: '2つめ',
                )
            ),
            TextField(
                controller: threeController,
                decoration: InputDecoration(
                  hintText: '3つめ',
                )
            ),

//テキストフォームを三つ設置しています。
//コントローラーを設置しています。

            ElevatedButton(
              onPressed: (){
                final _one = oneController.text;
                final _two = twoController.text;
                final _three = threeController.text;

//ボタンを押された際にコントローラーから入力された値を受け取っています。

                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => RouletteApp(
                      one: _one,
                      two: _two,
                      three: _three,
                    ),
                  ),
                );

//ボタンが押された際に次のroulette.dartに出てくるRouletteAppにコントローラーから受け取った値を受け渡しています。

              },
              child: Text(
                  'GO Roulette'
              ),

            )
          ],
        ),
      ),

    );
  }
}

ここは大きく変えました。画面はこちら

ここではテキストフォームを設置しているのが大きく変えたポイントです。また、次のルーレットの時に入力された値が反映されるようにコントローラーを設置しています。

【Flutter】テキストフィールドウィジェット

コントローラーはウィジェットの値を管理するためのクラスです。テキストを管理するのでTextEditingControllerを使用しています。

それを各テキストフォームに設置しておき、ボタンが押された際に一斉に取得して次のRouletteAppに受け渡すという流れにしています。

Roulette.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_fortune_wheel/flutter_fortune_wheel.dart';

class RouletteApp extends StatefulWidget {
  static const routeName = '/roulette_page';
  final String? one;
  final String? two;
  final String? three;

  const RouletteApp({
    Key? key,
    this.one,
    this.two,
    this.three,
  }) : super(key: key);

//このfinalとconstで値を先ほどのhome.dartから受け取っています。
//大事なのはStringに?をつけることです。テキストフォームの入力値はnullの可能性もあるので?でnull safetyにします。

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


class _ExamplePageState extends State<RouletteApp> {
  StreamController<int> selected = StreamController<int>();

  @override
  Widget build(BuildContext context) {
    final items = [
       widget.one,
       widget.two,
       widget.three,
    ];
//受け取った値をルーレットに入れています。
//Stateオブジェクトではwidgetとつけることで値を受け取れます。


    return Scaffold(
      appBar: AppBar(
        title: const Text('ルーレット'),
      ),
      body: GestureDetector(
        onTap: () {
          setState(() {
            selected.add(
              Fortune.randomInt(0, items.length),
            );
          });
        },
        child: Column(
          children: [
            Expanded(
              child: FortuneWheel(
                selected: selected.stream,
                items: [
                  for (var it in items) FortuneItem(child: Text(it!)),

//ここでもnull safetyのための!が設置されています。

                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

画像はこちら


https://qiita.com/keiy121/items/72656a932256ec43d893

値の受け渡しが全然わからなくて苦しみました。一番苦しんだのはnullsafetyの仕組みでした。
値の受け渡しを参考にしたのは以下です。
[Flutter]画面遷移の時に複数の値を渡すには
【Flutter】StatefulWidget に引数(Parameter)を渡すには - Qiita

値の受け渡し以外はほぼ変えてないのでそこまで大きな変化はないですが、結構大変でした。でもいい勉強になりました。。。

たぶんもっといい方法もあるのでしょうが、出来たならいいと言う方針で次に進みたいと思います。