Dart

Flutter x Riverpod でTextFieldの入力値を送信する

久しぶりの投稿です。

最近、業務でRiverpodを使っている影響でちょっとだけRiverpodのことが分かってきました。

Flutter x Riverpod

Flutter x RiverpodでのTextFieldの入力中の制御について解説します。

まずはサンプルアプリの画面を用意します。

main.dart

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('サンプル'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Row(
              children: [
                Text('メールアドレス'),
                SizedBox(
                  width: 20.0,
                ),
                Expanded(
                  child: TextFormField(
                    enabled: true,
                    style: TextStyle(color: Colors.black),
                    obscureText: false,
                    maxLines: 1,
                  ),
                ),
              ],
            ),
            ElevatedButton(
                onPressed: () {
                  print('送信');
                },
                child: Text('送信')
            )
          ],
        ),
      ),// This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

 

ビルドすると次のような画面が表示されます。

テキスト入力とボタンが存在します。

ここからRiverpodをインストールします。

pubspec.yamlを開いてRiverpodをインストールします。

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  flutter_riverpod: ^0.14.0+3

バージョンは意味なく最新版を指定しています。

今回は、ボタンをタップするとコンソールに入力したメールアドレスが表示される機能を実装します。

メールアドレス用のStateProviderの定義

main.dartに次のコードを定義します。

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// emailのcontrollerをStateProviderで定義する
final emailControllerStateProvider = StateProvider.autoDispose((ref) {
  return TextEditingController(text: '');
});

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

位置関係を明確にするためにimport文とmain関数の間に宣言しました。

今回はTextEditingControllerを使う形にします。(このために別の処理で泥沼にハマりました。)

RiverpodをWidget全体で使えるようにProviderScopeを定義する

Riverpodを使うための準備はまだあります。

Riverpodを適用させたいウィジェットにProviderScopeで囲う必要があります。

main.dart

void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}

StatelessWidgetをConsumerWidgetに書き換える

次に定義したStateProviderを監視するためにStatelessWidgetの部分をConsumerWidgetに書き換えます。これでwatch関数が使えるようになります。

class MyHomePage extends ConsumerWidget

メールアドレスの変更を監視するためにbuild関数を次のように変更します。

main.dart

@override
  Widget build(BuildContext context, ScopedReader watch) {
    // 中身は TextEditingController
    final emailControllerProvider = watch(emailControllerStateProvider);
    return Scaffold(
      appBar: AppBar(
        title: Text('サンプル'),
      ),

そして、TextFormFieldのcontrollerにこれをセットすればProviderとControllerが連携されます。

main.dart

Expanded(
                  child: TextFormField(
                    controller: emailControllerProvider.state,
                    enabled: true,
                    style: TextStyle(color: Colors.black),
                    obscureText: false,
                    maxLines: 1,
                  ),
                ),

あとは、送信ボタンをタップした時に定義したProviderをprintします。

main.dart

ElevatedButton(
                onPressed: () {
                  print(emailControllerProvider.state.text);
                },
                child: Text('送信')
            )

これで例えば、メールアドレスのテキスト入力欄に「sample@gmail.com」を入力して送信ボタンをタップするとコンソールに「sample@gmail.com」が表示されます。

Syncing files to device iPhone 12...
flutter: sample@gmail.com

これでRiverpodの基礎的な使い方です。ここから先がどんどん難しくなります。

Riverpod使いだしてまだ日が浅いので、ちょっと変更するにしても色々苦戦します。

全体のソースコード

全体のソースコードはこちらになります。

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// emailのcontrollerをStateProviderで定義する
final emailControllerStateProvider = StateProvider.autoDispose((ref) {
  return TextEditingController(text: '');
});

void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends ConsumerWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, ScopedReader watch) {
    // 中身は TextEditingController
    final emailControllerProvider = watch(emailControllerStateProvider);
    return Scaffold(
      appBar: AppBar(
        title: Text('サンプル'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Row(
              children: [
                Text('メールアドレス'),
                SizedBox(
                  width: 20.0,
                ),
                Expanded(
                  child: TextFormField(
                    controller: emailControllerProvider.state,
                    enabled: true,
                    style: TextStyle(color: Colors.black),
                    obscureText: false,
                    maxLines: 1,
                  ),
                ),
              ],
            ),
            ElevatedButton(
                onPressed: () {
                  print(emailControllerProvider.state.text);
                },
                child: Text('送信')
            )
          ],
        ),
      ),// This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
ABOUT ME
tamappe
都内で働くiOSアプリエンジニアのTamappeです。 当ブログではモバイルアプリの開発手法について紹介しています。メインはiOS、サブでFlutter, Android も対応できます。 執筆・講演のご相談は tamapppe@gmail.com までお問い合わせください。