How to move label text to top of the input text field only when I type some text

I want to move the label text to top of the input text field only when I enter some text. Currently it is moving on top when input text field is getting focus.

Widget nameField() {
    return TextFormField(
      keyboardType: TextInputType.text,
      autofocus: false,
      textAlign: TextAlign.start,
      textInputAction: TextInputAction.done,
      controller: nameTextEditingController,
      style: TextStyle(
          color: Colors.white, fontSize: 18, fontWeight: FontWeight.w500),
      decoration: const InputDecoration(
        contentPadding: EdgeInsets.symmetric(vertical: 15),
        labelText: Strings.user_info_page_name_placeholder,
        labelStyle: TextStyle(
            color: Colors.grey, fontSize: 18, fontWeight: FontWeight.w500),
        focusedBorder: OutlineInputBorder(
            borderSide: BorderSide(color: Colors.transparent, width: 1)),
      ),
    );
  }


I can think of two ways of doing this. Trick here is to use hintText:

First: using onChanged: method.

Code:

class MyClass extends StatefulWidget {
  @override
  _MyClassState createState() => new _MyClassState();
}

class _MyClassState extends State<MyClass> with SingleTickerProviderStateMixin {
  TextEditingController nameTextEditingController = TextEditingController();
  String _labelText;

  @override
  void initState() {
    super.initState();
   // nameTextEditingController.addListener(_hasStartedTyping);
  }

//  void _hasStartedTyping() {
//    setState(() {
//      if (nameTextEditingController.text.isNotEmpty) {
//        _labelText = 'Name';
//      } else {
//        _labelText = null;
//      }
//    });
//  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
          padding: EdgeInsets.symmetric(horizontal: 25, vertical: 30),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextFormField(
                keyboardType: TextInputType.text,
                autofocus: false,
                textAlign: TextAlign.start,
                onChanged: (v){
                  setState(() {
                    if(v.isNotEmpty){
                      _labelText = 'Name';
                    }else{
                      _labelText = null;
                    }
                  });

                },
                textInputAction: TextInputAction.done,
                controller: nameTextEditingController,
                style: TextStyle(
                    color: Colors.black87,
                    fontSize: 18,
                    fontWeight: FontWeight.w500),
                decoration: InputDecoration(
                  contentPadding: EdgeInsets.symmetric(vertical: 15),
                  labelText: _labelText,
                  hintText: 'Name',
                  hintStyle: TextStyle(
                      color: Colors.grey,
                      fontSize: 18,
                      fontWeight: FontWeight.w500),
                  labelStyle: TextStyle(
                      color: Colors.grey,
                      fontSize: 18,
                      fontWeight: FontWeight.w500),
                  focusedBorder: OutlineInputBorder(
                      borderSide:
                          BorderSide(color: Colors.transparent, width: 1)),
                ),
              ),
            ],
          )),
    );
  }
}

Second: using TextEditingController.addListener() method.

Code:

class MyClass extends StatefulWidget {
  @override
  _MyClassState createState() => new _MyClassState();
}

class _MyClassState extends State<MyClass> with SingleTickerProviderStateMixin {
  TextEditingController nameTextEditingController = TextEditingController();
  String _labelText;

  @override
  void initState() {
    super.initState();
    nameTextEditingController.addListener(_hasStartedTyping);
  }

  void _hasStartedTyping() {
    setState(() {
      if (nameTextEditingController.text.isNotEmpty) {
        _labelText = 'Name';
      } else {
        _labelText = null;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
          padding: EdgeInsets.symmetric(horizontal: 25, vertical: 30),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextFormField(
                keyboardType: TextInputType.text,
                autofocus: false,
                textAlign: TextAlign.start,
//                onChanged: (v){
//                  setState(() {
//                    if(v.isNotEmpty){
//                      _labelText = 'Name';
//                    }else{
//                      _labelText = null;
//                    }
//                  });
//
//                },
                textInputAction: TextInputAction.done,
                controller: nameTextEditingController,
                style: TextStyle(
                    color: Colors.black87,
                    fontSize: 18,
                    fontWeight: FontWeight.w500),
                decoration: InputDecoration(
                  contentPadding: EdgeInsets.symmetric(vertical: 15),
                  labelText: _labelText,
                  hintText: 'Name',
                  hintStyle: TextStyle(
                      color: Colors.grey,
                      fontSize: 18,
                      fontWeight: FontWeight.w500),
                  labelStyle: TextStyle(
                      color: Colors.grey,
                      fontSize: 18,
                      fontWeight: FontWeight.w500),
                  focusedBorder: OutlineInputBorder(
                      borderSide:
                          BorderSide(color: Colors.transparent, width: 1)),
                ),
              ),
            ],
          )),
    );
  }
}

Output: enter image description here


Know this was asked some time ago and the given answer probably worked for the time, but since this is the first hit on Google I'll add this more up-to-date answer

InputDecoration has floatingLabelBehavior property.

So adding floatingLabelBehavior: FloatingLabelBehavior.auto to your InputDecoration would do what you want.

So:

TextFormField(
  decoration: const InputDecoration(
    labelText: "Click me",
      floatingLabelBehavior: FloatingLabelBehavior.auto),
),

DartPad: https://dartpad.dev/?ffc1844e90bb8343d90b14c7887c9de1