広告 Flutter Dart Unity アプリ開発

ダイアログボックスを表示する

警告のみのダイアログボックス、文字入力ありのダイアログボックスの2種類を扱えるdialogutils.dartを使う。
以下のURLの記事を参考に改良しました。多国語対応と、カレンダー日付入力機能を追加しています。

Flutter逆引き辞典 Chapter 16 ダイアログでもテキスト入力がしたい
https://zenn.dev/pressedkonbu/books/flutter-reverse-lookup-dictionary/viewer/016-input-text-on-dialog

ソースファイル

以下のファイルをlibフォルダに入れておく。HomePage.dart等で、インポートして使う。(カレンダ部分は多国語対応している)。

dialogutil.dart

//dialogutil.dart

// 注意:入力制限は要修正です。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:flutter_localization/flutter_localization.dart';

class DialogUtils {
  DialogUtils._();
  final FlutterLocalization localization = FlutterLocalization.instance;

  /// タイトルのみを表示するシンプルなダイアログを表示する
  static Future<void> showOnlyTitleDialog(
    BuildContext context,
    String title,
  ) async {
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(title: Text(title));
      },
    );
  }

  /// 入力した文字列を返すダイアログを表示する
  static Future<String?> showEditingDialog(
    BuildContext context,
    String text,
  ) async {
    return showDialog<String>(
      context: context,
      builder: (context) {
        return TextEditingDialog(text: text);
      },
    );
  }

  // カレンダーで日付を選択するダイアログボックス(yyyy-MM-dd文字列を返す)
  static Future<String?> showCalender(
    BuildContext context,
    String sDate,
  ) async {
    final FlutterLocalization localization = FlutterLocalization.instance;
    String sLoc = localization.currentLocale.localeIdentifier.substring(
      0,
      2,
    ); // 頭2文字
    debugPrint(sLoc);
    DateTime dt = DateTime.parse(sDate);
    DateFormat dateF = DateFormat('yyyy-MM-dd'); // 時刻を消すために使用

    DateTime? picked = await showDatePicker(
      context: context,
      initialDate: dt,
      firstDate: DateTime(DateTime.now().year - 120),
      lastDate: DateTime(DateTime.now().year + 120),
      locale: Locale(sLoc),
      keyboardType: TextInputType.text,
    );

    DateTime d = picked ?? dt;
    String sDate2 = dateF.format(d);
    return sDate2;
  }
}

/// 状態を持ったダイアログ
class TextEditingDialog extends StatefulWidget {
  const TextEditingDialog({super.key, this.text});
  final String? text;

  @override
  State<TextEditingDialog> createState() => _TextEditingDialogState();
}

class _TextEditingDialogState extends State<TextEditingDialog> {
  final controller = TextEditingController();
  final focusNode = FocusNode();
  @override
  void dispose() {
    controller.dispose();
    focusNode.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    // TextFormFieldに初期値を代入する
    controller.text = widget.text ?? '';
    focusNode.addListener(() {
      // フォーカスが当たったときに文字列が選択された状態にする
      if (focusNode.hasFocus) {
        controller.selection = TextSelection(
          baseOffset: 0,
          extentOffset: controller.text.length,
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      content: TextFormField(
        autofocus: true, // ダイアログが開いたときに自動でフォーカスを当てる
        focusNode: focusNode,
        controller: controller,
        // ================================================================機能制限(要修正)
        // 数字のみ許容
        keyboardType: TextInputType.number,
        inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[0-9.]'))],

        // テキスト入力可能(ただしアルファベットのみ)
        //keyboardType: TextInputType.text,
        //inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9._-]'))],

        onFieldSubmitted: (_) {
          // エンターを押したときに実行される
          Navigator.of(context).pop(controller.text);
        },
      ),
      actions: [
        TextButton(
          onPressed: () {
            debugPrint(controller.text);
            Navigator.of(context).pop(controller.text);
          },
          child: const Text('OK'),
        ),
      ],
    );
  }
}

ダイアログボックスの呼び出し方法

数値を入力する場合について例示する。stateオブジェクトの、build のScaffold()内に、下記を参考に記載する。
ローカル変数textBufで文字列を受取り、初期値を「0」として、nullなら「0」文字列を発生させる。(String?型なのでnullが有り得る)
int.parse(testBuf)でintに変換後、有効な値なら、setState(() {.....}で、共有変数に更新をかける。

async , await が必須。

  @override
  Widget build(BuildContext context) {
    final int age =0;
    ........
    return Scaffold(
      appBar: AppBar(....),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            ......    
            ElevatedButton(
              onPressed: () async {
                String textBuf =  await DialogUtils.showEditingDialog(context, '0') ?? '0';
                debugPrint(textBuf);
                int num = int.parse(textBuf);
                if (num > 0) {
                  setState(() {
                    selecteddate2 = selecteddate1.add(Duration(days: num),);
                  });
                } // if
              }, 
              child: const Text('日数'),
            ), // ElevatedButton
.......

カレンダー入力ダイアログの呼び出し方法

import 'package:intl/intl.dart';  // DateFormat 関数で必要
// import 'package:flutter_localization/flutter_localization.dart'; // 多国語対応モジュールここでは使わない
// final FlutterLocalization localization = FlutterLocalization.instance; //多国語対応インスタンス
// String sLoc = localization.currentLocale.localeIdentifier.substring(0,2,); // ’ja’となる。

DateTime birthday = DateTime.parse('1900-01-01'); //仮の初期値 意味はない
DateFormat dateF = DateFormat('yyyy-MM-dd'); // 時刻を消すために使用
......

              Text(’生年月日’),
              Text(DateFormat.yMMMEd('ja').format(birthday);, context),
              ),
              ElevatedButton(
                onPressed: () async {
                  String? sBDay = await DialogUtils.showCalender(
                    context,
                    dateF.format(birthday),
                  );
                  if (sBDay != null) {
                    setState(() {
                      birthday = DateTime.parse(sBDay);
                    });
                  }
                },
......

-Flutter Dart Unity アプリ開発