15
10

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】TextFormField タップ時にピッカー(ドラムロール)を出して入力させる

Posted at

Flutter-1.20.2 Dart-2.9.1

フォームを作成するとき TextFormField を用いて実装することが多いですが、キーボードによるテキスト入力ではなく、選択肢から選ばせたい場合があります。
独自のウィジェットを作成しても良いですが、 TextFormField として実装することで、他の TextFormField と同じように onSave() を処理したり、バリデーションを適応することができます。

「テキストフィールドをタップすると、ピッカー(ドラムロール)が表示され、選択したものがフォームに入力される」というものを実装します。

まず普通のテキストフィールドを作成します。

main.dart
TextFormField buildTextFormField(BuildContext context) {
    return TextFormField(
      decoration: const InputDecoration(hintText: 'テキストを入力'),
    );
  }

onTap() でタップした時にピッカーを呼び出します。
ピッカー部分の実装は以前の投稿を参照。
【Flutter】画面下から出てくるピッカー(ドラムロール)を実装する

main.dart
TextFormField buildTextFormField(BuildContext context) {
  return TextFormField(
    onTap: () {
      // キーボードが出ないようにする
      FocusScope.of(context).requestFocus(new FocusNode());
      showPicker();
    },
    decoration: const InputDecoration(hintText: 'テキストを入力'),
  );
}

void showPicker() {
  final list = ['選択肢1', '選択肢2', '選択肢3'];
  final _pickerItems = list.map((item) => Text(item)).toList();
  var selectedIndex = 0;

  showCupertinoModalPopup<void>(
    context: context,
    builder: (BuildContext context) {
      return Container(
        height: 216,
        child: GestureDetector(
          onTap: () {
            Navigator.pop(context);
          },
          child: CupertinoPicker(
            itemExtent: 32,
            children: _pickerItems,
            onSelectedItemChanged: (int index) {
              selectedIndex = index;
            },
          ),
        ),
      );
    },
  );
}

テキストフィールドをタップするとピッカーが起動するようになります。

そのままだとピッカーが出る前にキーボードが一瞬表示されてしまうので、
FocusScope.of(context).requestFocus(new FocusNode()) を入れて抑制しています。

Simulator Screen Shot - iPhone SE (2nd generation) - 2020-08-31 at 09.33.42.png

ピッカーを閉じたとき、選択した文字列を TextFormField に反映します。

main.dart
// コントローラーを追加
final TextEditingController _controller = TextEditingController();

TextFormField buildTextFormField(BuildContext context) {
    return TextFormField(
      onTap: () {
        // ...
      },
      // コントローラーを追加
      controller: _controller,
      decoration: const InputDecoration(hintText: 'テキストを入力'),
    );
  }
main.dart
showCupertinoModalPopup<void>(
  // ...
).then((_) {
  if (selectedIndex != null) {
    _controller.value = TextEditingValue(text: list[selectedIndex]);
  }
});

Simulator Screen Shot - iPhone SE (2nd generation) - 2020-08-31 at 09.33.49.png

TextFormField として実装しているため、validator()onSave() を実装することができます。

コード全体
main.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TextFormField Picker',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const MyHomePage(title: 'TextFormField Picker'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: buildTextFormField(context),
        ));
  }

  TextFormField buildTextFormField(BuildContext context) {
    return TextFormField(
      onTap: () {
        // キーボードが出ないようにする
        FocusScope.of(context).requestFocus(new FocusNode());
        showPicker();
      },
      controller: _controller,
      decoration: const InputDecoration(hintText: 'テキストを入力'),
    );
  }

  void showPicker() {
    final list = ['選択肢1', '選択肢2', '選択肢3'];
    final _pickerItems = list.map((item) => Text(item)).toList();
    var selectedIndex = 0;

    showCupertinoModalPopup<void>(
      context: context,
      builder: (BuildContext context) {
        return Container(
          height: 216,
          child: GestureDetector(
            onTap: () {
              Navigator.pop(context);
            },
            child: CupertinoPicker(
              itemExtent: 32,
              children: _pickerItems,
              onSelectedItemChanged: (int index) {
                selectedIndex = index;
              },
            ),
          ),
        );
      },
    ).then((_) {
      if (selectedIndex != null) {
        _controller.value = TextEditingValue(text: list[selectedIndex]);
      }
    });
  }
}
15
10
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
15
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?