質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

解決済

1回答

592閲覧

入力フォームに文字が入力された時のみボタンを有効化したい

t_flutter

総合スコア7

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2023/03/04 13:31

実現したいこと

TextFormFieldに文字が入力された時だけ登録ボタンを有効化したい。

前提

flutterで画像の選択、それに紐づくタイトルを入力、具材を選択して登録できるようなアプリを勉強がてら作っています。
今回はタイトルの入力と登録部分についてです。
タイトルをTextFormFieldに入力して入力が出来ていれば登録ボタンを押下できるようにしたいと思っています。
何も入力されていなければ登録ボタンは無効化したいと思っています。

発生している問題・エラーメッセージ

まず、TextFormFieldに文字が入力されている時はtrue,そうでない時はfalseになるような判定用のbool型変数であるinputnameを
用意し初期値はfalseにしました。

以下のように
入力されているかどうかを判定するために
TextFormFieldにautovalidateMode:AutovalidateMode.onUserInteraction
を設定しvalueが空の時はinputnameをfalseに、入力されている時はtrueにするようにしています。

TextFormField( autovalidateMode: AutovalidateMode.onUserInteraction, validator: (value) { if (value!.isEmpty) { inputname = false; //確認用 print("${inputname}になった"); } else { inputname = true; //確認用 print("${inputname}になった"); } }, style: const TextStyle(color: Colors.grey), decoration: const InputDecoration( //間接的にTextFormFieldの高さを指定 contentPadding: EdgeInsets.symmetric(vertical: 40), hintText: " 料理名を入力...", hintStyle: TextStyle( color: Colors.grey, ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey, width: 1)), enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey, width: 1), ), fillColor: Colors.black, //fillColorに設定した背景色を有効化 filled: true), ),

また、同じ画面のAppBarに登録ボタンを用意しており、inputnameがtrueの時はNavigator.popで呼び出し元の画面に遷移し、inputnameがfalseの時はnullでボタンを無効化しています。

TextButton( //inputnameがtrueの時のみボタンを有効化する onPressed: inputname ? () { //SelectImage画面とRegisterItem画面を破棄して最初の画面に戻る Navigator.popUntil(context, (route) => route.isFirst); } : null, child: const Text( "登録", style: TextStyle(color: Colors.white, fontSize: 20), ), ),

ここで、inputnameを基に条件分岐が出来ると思っていたのですがどうやら初期値のfalseのまま変更されていないようで常にボタンが無効化されたままであり、なぜ値を入力してもonpressedの条件式であるinputnameがtrueにならないのか分からず悩んでいます。アドバイス宜しくお願いします。

試したこと

validator側の条件分岐で値が空の時にinputname=falseになっていること、入力時に値がtrueになっていることは確認出来ています。

ソースコード

//料理の具材とタイトルを登録する class RegisterItem extends StatefulWidget { const RegisterItem({super.key, required this.stateSetter}); final Function stateSetter; @override _RegisterItem createState() => _RegisterItem(); } class _RegisterItem extends State<RegisterItem> { //料理名を入力したかの判断 bool inputname = false; //登録可能な食材の一覧 final tags = [ 'キャベツ', 'レタス', '白菜', 'キュウリ', 'トマト', 'ネギ', 'エリンギ', 'マイタケ', '玉ねぎ', 'ニンニク', 'キムチ', '卵', 'ケチャップ', 'マヨネーズ', 'チーズ', 'コンソメ', '味噌', 'ナス', '醤油', 'みりん', '塩', 'コショウ', ]; /// 選択されたタグ var selectedTags = <String>[]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.black, title: Stack( alignment: Alignment.center, children: <Widget>[ Align( alignment: Alignment.centerRight, child: ButtonTheme( padding: const EdgeInsets.symmetric(vertical: 8), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, minWidth: 0, height: 0, child: TextButton( //inputnameがtrueの時のみボタンを有効化する onPressed: inputname ? () { //SelectImage画面とRegisterItem画面を破棄して最初の画面に戻る Navigator.popUntil(context, (route) => route.isFirst); } : null, child: const Text( "登録", style: TextStyle(color: Colors.white, fontSize: 20), ), ), ), ), ], ), ), body: Container( alignment: Alignment.topCenter, color: Colors.black, height: double.infinity, width: double.infinity, //height: size.height, child: SingleChildScrollView( child: Column( children: <Widget>[ TextFormField( autovalidateMode: AutovalidateMode.onUserInteraction, validator: (value) { if (value!.isEmpty) { inputname = false; //確認用 print("${inputname}になった"); } else { inputname = true; //確認用 print("${inputname}になった"); } }, style: const TextStyle(color: Colors.grey), decoration: const InputDecoration( //間接的にTextFormFieldの高さを指定 contentPadding: EdgeInsets.symmetric(vertical: 40), hintText: " 料理名を入力...", hintStyle: TextStyle( color: Colors.grey, ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey, width: 1)), enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey, width: 1), ), fillColor: Colors.black, //fillColorに設定した背景色を有効化 filled: true), ), Container( width: double.infinity, decoration: const BoxDecoration(color: Colors.black), //材料一覧を表示する child: Column( children: [ const SizedBox(height: 10, width: double.infinity), ElevatedButton( onPressed: () { selectedTags.clear(); setState(() {}); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.black, //ボタンの背景色 side: const BorderSide( color: Colors.grey, //枠線! width: 3, //枠線! ), ), child: const Text( '選択クリア', style: TextStyle( color: Colors.yellow, fontSize: 20, ), ), ), const SizedBox(height: 10, width: double.infinity), Wrap( runSpacing: 16, spacing: 16, children: tags.map((tag) { // selectedTags の中に自分がいるかを確かめる final isSelected = selectedTags.contains(tag); return InkWell( borderRadius: const BorderRadius.all(Radius.circular(32)), onTap: () { if (isSelected) { // すでに選択されていれば取り除く selectedTags.remove(tag); } else { // 選択されていなければ追加する selectedTags.add(tag); } setState(() {}); }, //ボタンをContainerで作製 child: AnimatedContainer( duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8), decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(32)), border: Border.all( width: 2, color: Colors.pink, ), color: isSelected ? Colors.pink : null, ), child: Text( tag, style: TextStyle( color: isSelected ? Colors.white : Colors.pink, fontWeight: FontWeight.bold, ), ), ), ); }).toList(), ), const SizedBox(height: 20, width: double.infinity), ], ), ), ], ), ), ), ); } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

TextFormFieldにonChangedフィールドが用意されているので下記のようにするのが良さそうです。

child: TextFormField( onChanged:(value){ if(value.isEmpty){ setState((){ inputname = false; }); //確認用 print("${inputname}になった"); } else { setState((){ inputname = true; }); //確認用 print("${inputname}になった"); } },

投稿2023/03/05 01:40

moriman

総合スコア615

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t_flutter

2023/03/05 14:25

morimanさん、ご回答ありがとうございます。無事作ろうとしていた機能が実現出来ました。なるほどonChangedの中でsetStateを使うのですね。ちなみに validator: (value) { if (value!.isEmpty) { setState(() { inputname = false; }); } とするとbuild中にStateを変更するなといったエラーが出てしまったためここでsetStateを実行するものではないという思い込みからsetStateを使うことを排除してしまっていました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問