61
votes

I need to disable TextFormField occasionally. I couldn't find a flag in the widget, or the controller to simply make it read-only or disable. What is the best way to do it?

13
For people from google, you can now add a flag on the widget, see my answer. - Benten
@Arash can you change the accepted answer to one of the more recent ones because the framework now supports this - geg

13 Answers

22
votes

This isn't a feature that is currently provided by the framework, but you can use a FocusScope to prevent a TextFormField from requesting focus.

Here's what it looks like when it's disabled.

(with hint text) empty and readonly

(with a readonly value) readonly

Here's what it looks like when it's enabled.

(with focus) focused

(without focus) editable

Code for this is below:

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: new HomePage(),
  ));
}

class HomePage extends StatefulWidget {
  HomePageState createState() => new HomePageState();
}

class HomePageState extends State<HomePage> {

  TextEditingController _controller = new TextEditingController();
  bool _enabled = false;

  @override
  Widget build(BuildContext context) {
    ThemeData theme = Theme.of(context);
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Disabled Text'),
      ),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.free_breakfast),
        onPressed: () {
          setState(() {
            _enabled = !_enabled;
          });
        }
      ),
      body: new Center(
        child: new Container(
          margin: const EdgeInsets.all(10.0),
          child: _enabled ?
          new TextFormField(controller: _controller) :
          new FocusScope(
            node: new FocusScopeNode(),
            child: new TextFormField(
              controller: _controller,
              style: theme.textTheme.subhead.copyWith(
                color: theme.disabledColor,
              ),
              decoration: new InputDecoration(
                hintText: _enabled ? 'Type something' : 'You cannot focus me',
              ),
            ),
          ),
        ),
      ),
    );
  }
}
115
votes

There is another way this can be achieved which also does not cause this issue. Hope this might help someone.

Create AlwaysDisabledFocusNode and pass it to the focusNode property of a TextField.

class AlwaysDisabledFocusNode extends FocusNode {
  @override
  bool get hasFocus => false;
}

then

new TextField(
    enableInteractiveSelection: false, // will disable paste operation
    focusNode: new AlwaysDisabledFocusNode(),
    ...
    ...
)

Update: TextField now has enabled property. Where you can just disable the TextField like

new TextField(
    enabled: false, 
    ...
    ...
)

Note: This will also disable icon associated with text input.

90
votes
TextFormField(
readOnly: true,
)
62
votes

TextField and TextFormField both have an argument called enabled. You can control it using a boolean variable. enabled=true means it will act as an editing text field whereas enabled=false will disable the TextField.

25
votes

Similar to readonly like in html

TextField(
    enableInteractiveSelection: false,
    focusNode: FocusNode(),
)

This can response to onTap.


Similar to disabled like in html

TextField(
    enable: false
)

This can not response to onTap.

17
votes

This is another way of somehow disabling a TextField but keeping it's functionality. I mean for onTap usage

TextField(
    enableInteractiveSelection: false,
    onTap: () { FocusScope.of(context).requestFocus(new FocusNode()); },
)
  • enableInteractiveSelection

    will disable content selection of TextField

  • FocusScope.of(context).requestFocus(new FocusNode());

    change the focus to an unused focus node

Using this way, you can still touch TextField but can't type in it or select it's content. Believe me it's going to be useful sometimes ( datepicker, timepicker, ... ) :)

14
votes

Use readOnly:true is correct. But if you still want focus to this text field you can follow below code:

TextFormField(
  showCursor: true,//add this line
  readOnly: true
)

And if you want hide text pointer (cursor), you need set enableInteractiveSelection to false.

12
votes

There is now a way to disable TextField and TextFormField. See github here. Use it like this:

TextField(enabled: false)
11
votes

I have used a combination of readOnly and enableInteractiveSelection properties to achieve the desired behavior on TextField.

TextField(
  readOnly: true,
  enableInteractiveSelection: true,
  onTap: () {
    do_something(),
  },
)

With enableInteractiveSelection set to true, it will allow onTap() to function as normal.

7
votes

I tried using FocuseNode(), enabled = false yet not working, Instead of that I use a widget called AbsorbPointer. It's use for preventing a widget from touch or tap, I wrap my TextFormField or other widget inside AbsordPointer Widgets and give a parameter to disable from touch

Example

AbsorbPointer(
      absorbing: true,  //To disable from touch use false while **true** for otherwise
      child: Your WidgetsName
);
1
votes

Use readOnly: true

TextField(
  readOnly: true,
  controller: controller,
  obscureText: obscureText,
  onChanged: (value) {
    onValueChange();
  },
  style: TextStyle(
    color: ColorResource.COLOR_292828,
    fontFamily: Font.AvenirLTProMedium.value,
    fontSize: ScreenUtil().setHeight(Size.FOURTEEN)),
    decoration: InputDecoration(
    border: InputBorder.none,
    hintText: hint,
    hintStyle: TextStyle(
      fontSize: ScreenUtil().setHeight(Size.FOURTEEN),
      color: ColorResource.COLOR_HINT,
      fontFamily: Font.AvenirLTProBook.value)),
  ),
1
votes

It has enabled key, this is doing fine for me.

TextFormField(
    enabled: false,
)
-1
votes

use enabled: false in TextField

TextField( enabled: false, decoration: new InputDecoration( suffixIcon: IconButton( onPressed: () => {}, icon: Icon( Icons.arrow_drop_down, color: Colors.black, ), ), border: new UnderlineInputBorder( borderSide: new BorderSide(color: Colors.red))), )