Flutter 数値表示・入力ダイアログのサンプル

はじめに

Flutterで数値を入力するためのダイアログパターンを3つ作ってみました(iPad向けです)。

https://github.com/sshiraki/FlutterNumberDisplay

スクリーンショット 2020-03-08 21.51.26


メインで表示されるページのラジオボタンで表示させるダイアログを選択し、数字の部分をタップするとダイアログが表示されます。

どれも、シンプルに数値を入力するだけで、他に機能はありません。

 白枠:白い枠にテンキーを配置

 透過:グレイの透過背景にテンキーを配置

 ボトムシート:ボトムシートにテンキーを配置

最初に表示される数値をタップするとダイアログが表示され、ダイアログで入力された数値がEnterキーをタップすることで確定され、ダイアログが閉じます。

は後ろの画面に表示されている数値が変更される想定ですが、現状は見た目では数値が変更されません。

ダイアログについて

「白枠」、と「透過」は showDialogメソッドでDialogウィジェット を表示しします。

main.dart : Scaffold:body

                         result = await showDialog(
                             barrierDismissible: false,
                             context: context,
                             builder: (_) {
                               if (_dialogType == DialogType.greyFrame) {
                                 return NumberDisplayDialogGrey(
                                     numberData: "$numberData");
                               } else {
                                 //_dialogType == DialogType.whiteFrame
                                 return NumberDisplayDialog(
                                     numberData: "$numberData");
                               }
                             });
                         setState(() {
                           numberData = result;
                         });

スクリーンショット 2020-03-08 21.25.16

白枠


スクリーンショット 2020-03-08 21.56.18

透過

「ボトムシート」はshowModalBottomSheet でモーダルボトムシートを表示します。

モーダルボトムシートは厳密にはダイアログではありませんが、本稿ではダイアログとして扱っています。

main.dart : Scaffold:body

                     if (_dialogType == DialogType.bottomSheet) {
                         result = await showModalBottomSheet<String>(
                           context: context,
                           isDismissible: false,
                           builder: (BuildContext context) {
                             return NumberDisplayBottomSheet(
                                 numberData: "$numberData");
                           },
                         );

                         setState(() {
                          if (result != null) {
                             numberData = result;
                           }
                         });

ModalBottomSheetでは、後ろに表示されているグレイアウトされた部分をタップした場合、何もしなければ、戻り値なしでダイアログが終了してしまいます。setStateに以下の処理があることで、グレイ部分をタップしても終了しなくなります。

                         setState(() {
                           if (result != null) {
                             numberData = result;
                           }
                         });

一見、戻り値がnullの場合、ダイアログが終了してしまいそうですが、ダイアログに処理が戻ります。戻り値がnullでない場合はnumberDataに値が設定され、ダイアログが終了します。

スクリーンショット 2020-03-08 21.33.35

ボトムシート


ステート保持について

ボタンのUIはAdobe XD to Flutter Generate Plugin を使用してベースを作りましたが、ボタンの処理を実装したり、ステート保持をするため、大幅に修正しています。

Adobe XD でフロントエンド設計(Adobe XD Flutter Code Generate プラグイン)
https://note.com/sshiraki/n/n8270cec70534

ステートは、providerを使用しダイアログの数値表示部分を外出ししています。メイン画面のステート保持は分離する実装としたため、「ボトムシート」では見た目で数値が変更されませんが、内部的にはproviderでステート保持されています。

providerを使えるようにします。

main.dart

import 'package:provider/provider.dart';


数値表示部分のステートを外出ししています。

NumberDataModel.dart

import 'package:flutter/material.dart';

class NumberDataModel extends ChangeNotifier {
 final String _numberData_default = "000000";
 String numberData;
 NumberDataModel({Key key, this.numberData});
 String getNumberData() {
   return numberData;
   //print("debug  $numberData");
 }
 void setNumberData(String s) {
   if (numberData.substring(0, 1) == "0") {
     numberData = "${numberData.substring(1, 6)}$s";
     notifyListeners();
     //print("debug  $numberData");
   }
 }
 void delNumberData() {
   numberData = "0${numberData.substring(0, 5)}";
   notifyListeners();
   //print("debug $numberData");
 }
 void resetNumberData() {
   numberData = _numberData_default;
   notifyListeners();
   //print("debug $numberData");
 }
}


ボタンの処理。数値を設定する前にモデル(NumberDataModel)を指定します。

main.dart : _NumberDisplayDialogState
NumberDisplayBottomSheet.dart : _NumberDisplayBottomSheetState
NumberDisplayDialogGrey.dart : _NumberDisplayDialogGreyState

ChangeNotifierProvider<NumberDataModel>(
     create: (_) => NumberDataModel(numberData: _numberData)


数値(文字列ですが)を画面表示します(1文字ずつ表示するため、substringで切り出し)。

main.dart : NumberDisplayText

       Text(
           Provider.of<NumberDataModel>(context)
               .numberData
               .substring(inx, inx + 1)


テンキーボタンの表示と押された時の処理。Consumerでモデル(NumberDataModel)を指定します。

main.dart : KeyButton, KeyButtonBS, KeyButtonClear, KeyButtonEnter

       Consumer<NumberDataModel>(builder: (_, model, __) {


数値のボタンを押された時の処理。NumberDataModelのsetNumberDataを呼びます。引数keychは"1”〜"9"。

main.dart : KeyButton

             onPressed: () {
               model.setNumberData(keych);
             },


バックスペースキーが押された時の処理。NumberDataModelのdelNumberDataを呼びます。

main.dart : KeyButtonBS

              onPressed: () {
               model.delNumberData();
             }


Cキーが押された時の処理。NumberDataModelのresetNumberDataを呼びます。

main.dart : KeyButtonClear

              onPressed: () {
               model.resetNumberData();
             },


Enterキーが押された時の処理。NumberDataModelのgetNumberDataで取得した値を親画面に戻します。

main.dart : KeyButtonEnter

                onPressed: () {
                 //print("debug ${model.getNumberData()}");
                 Navigator.of(context).pop("${model.getNumberData()}");
               }

以上です。


この記事が気に入ったらサポートをしてみませんか?