Search code examples
flutterdartbutton

How do I disable a Button in Flutter?


I'm having trouble figuring out how to set the enabled state of a button in Flutter.

From the docs, it says to set onPressed to null to disable a button, and give it a value to enable it. This is fine if the button continues to be in the same state for the lifecycle.

I get the impression I need to create a custom Stateful widget that will allow me to update the button's enabled state (or onPressed callback) somehow.

How would I do that? This seems like a pretty straightforward requirement, but I can't find anything in the docs on how to do it.


Solution

  • I think you may want to introduce some helper functions to build your button as well as a Stateful widget along with some property to key off of.

    • Use a StatefulWidget/State and create a variable to hold your condition (e.g. isButtonDisabled)
    • Set this to true initially (if that's what you desire)
    • When rendering the button, don't directly set the onPressed value to either null or some function onPressed: () {}
    • Instead, conditionally set it using a ternary or a helper function (example below)
    • Check the isButtonDisabled as part of this conditional and return either null or some function.
    • When the button is pressed (or whenever you want to disable the button) use setState(() => isButtonDisabled = true) to flip the conditional variable.
    • Flutter will call the build() method again with the new state and the button will be rendered with a null press handler and be disabled.

    Here's is some more context using the Flutter counter project.

    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
      bool _isButtonDisabled;
    
      @override
      void initState() {
        _isButtonDisabled = false;
      }
    
      void _incrementCounter() {
        setState(() {
          _isButtonDisabled = true;
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text("The App"),
          ),
          body: new Center(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Text(
                  'You have pushed the button this many times:',
                ),
                new Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.display1,
                ),
                _buildCounterButton(),
              ],
            ),
          ),
        );
      }
    
      Widget _buildCounterButton() {
        return new RaisedButton(
          child: new Text(
            _isButtonDisabled ? "Hold on..." : "Increment"
          ),
          onPressed: _isButtonDisabled ? null : _incrementCounter,
        );
      }
    }
    

    In this example I am using an inline ternary to conditionally set the Text and onPressed, but it may be more appropriate for you to extract this into a function (you can use this same method to change the text of the button as well):

    Widget _buildCounterButton() {
        return new RaisedButton(
          child: new Text(
            _isButtonDisabled ? "Hold on..." : "Increment"
          ),
          onPressed: _counterButtonPress(),
        );
      }
    
      Function _counterButtonPress() {
        if (_isButtonDisabled) {
          return null;
        } else {
          return () {
            // do anything else you may want to here
            _incrementCounter();
          };
        }
      }