実現したいこと
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), ], ), ), ], ), ), ), ); } }

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/03/05 14:25