Search code examples
formsflutterkeyboarduser-inputshowdialog

Flutter how to get user input using text form in show dialog?


I'm trying to get the user input to change the title using a text form in show dialog but it seems the state is rebuilding whenever the keyboard shows/closes, my code is working before, but when I did flutter upgrade to v1.17 it's not working anymore. I've been stuck here for a couple of days now and I don't know what's wrong with my code or what error might be causing it, I can only see "getSelectedText on inactive InputConnection" and "mSecurityInputMethodService is null" in the debug console, please help.

Here's a sample of my code:

import 'package:flutter/material.dart';

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  final TextEditingController titleController = new TextEditingController();
  final GlobalKey<FormState> _keyDialogForm = new GlobalKey<FormState>();

  @override
  void initState() {
    super.initState();

    titleController.text = 'Hello';
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        resizeToAvoidBottomInset: false,
        body: Center(
          child: Column(
            children: <Widget>[
              Text(titleController.text),
              SizedBox(
                height: 50,
              ),
              FlatButton(
                  color: Colors.redAccent,
                  onPressed: () {
                    showTitleDialog();
                  },
                  child: Text(
                    'Show Dialog',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      color: Colors.white,
                    ),
                  ))
            ],
          ),
        ));
  }

  Future showTitleDialog() {
    return showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Form(
              key: _keyDialogForm,
              child: Column(
                children: <Widget>[
                  TextFormField(
                    decoration: const InputDecoration(
                      icon: Icon(Icons.ac_unit),
                    ),
                    maxLength: 8,
                    textAlign: TextAlign.center,
                    onSaved: (val) {
                      titleController.text = val;
                    },
                    autovalidate: true,
                    validator: (value) {
                      if (value.isEmpty) {
                        return 'Enter Title Name';
                      }

                      return null;
                    },
                  )
                ],
              ),
            ),
            actions: <Widget>[
              FlatButton(
                onPressed: () {
                  if (_keyDialogForm.currentState.validate()) {
                    _keyDialogForm.currentState.save();

                    Navigator.pop(context);
                  }
                },
                child: Text('Save'),
                color: Colors.blue,
              ),
              FlatButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: Text('Cancel')),
            ],
          );
        });
  }
}

Solution

  • You can copy paste run full code below
    You can call setState in onSaved
    code snippet

    onSaved: (val) {
                      titleController.text = val;
                      setState(() {});
                    },
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.dart';
    
    class Test extends StatefulWidget {
      @override
      _TestState createState() => _TestState();
    }
    
    class _TestState extends State<Test> {
      final TextEditingController titleController = new TextEditingController();
      final GlobalKey<FormState> _keyDialogForm = new GlobalKey<FormState>();
    
      @override
      void initState() {
        super.initState();
    
        titleController.text = 'Hello';
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            resizeToAvoidBottomInset: false,
            body: Center(
              child: Column(
                children: <Widget>[
                  Text(titleController.text),
                  SizedBox(
                    height: 50,
                  ),
                  FlatButton(
                      color: Colors.redAccent,
                      onPressed: () {
                        showTitleDialog();
                      },
                      child: Text(
                        'Show Dialog',
                        style: TextStyle(
                          fontWeight: FontWeight.bold,
                          color: Colors.white,
                        ),
                      ))
                ],
              ),
            ));
      }
    
      Future showTitleDialog() {
        return showDialog(
            context: context,
            builder: (BuildContext context) {
              return AlertDialog(
                title: Form(
                  key: _keyDialogForm,
                  child: Column(
                    children: <Widget>[
                      TextFormField(
                        decoration: const InputDecoration(
                          icon: Icon(Icons.ac_unit),
                        ),
                        maxLength: 8,
                        textAlign: TextAlign.center,
                        onSaved: (val) {
                          titleController.text = val;
                          setState(() {});
                        },
                        autovalidate: true,
                        validator: (value) {
                          if (value.isEmpty) {
                            return 'Enter Title Name';
                          }
    
                          return null;
                        },
                      )
                    ],
                  ),
                ),
                actions: <Widget>[
                  FlatButton(
                    onPressed: () {
                      if (_keyDialogForm.currentState.validate()) {
                        _keyDialogForm.currentState.save();
    
                        Navigator.pop(context);
                      }
                    },
                    child: Text('Save'),
                    color: Colors.blue,
                  ),
                  FlatButton(
                      onPressed: () {
                        Navigator.pop(context);
                      },
                      child: Text('Cancel')),
                ],
              );
            });
      }
    }
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: Test(),
        );
      }
    }