¿Cómo desactivo un botón en Flutter?

115

Estoy empezando a acostumbrarme a Flutter, pero tengo problemas para averiguar cómo configurar el estado habilitado de un botón.

En los documentos, dice establecer onPresseden nulo para deshabilitar un botón y darle un valor para habilitarlo. Esto está bien si el botón continúa en el mismo estado durante el ciclo de vida.

Tengo la impresión de que necesito crear un widget Stateful personalizado que me permita actualizar el estado habilitado del botón (o la devolución de llamada onPressed) de alguna manera.

Entonces mi pregunta es ¿cómo haría eso? Esto parece un requisito bastante sencillo, pero no puedo encontrar nada en los documentos sobre cómo hacerlo.

Gracias.

chris84948
fuente
¿Puede aclarar lo que quiere decir con "Esto está bien si el botón continúa en el mismo estado durante el ciclo de vida"? ?
Seth Ladd

Respuestas:

127

Creo que es posible que desee introducir algunas funciones auxiliares en buildsu botón, así como un widget con estado junto con alguna propiedad para eliminar.

  • Use un StatefulWidget / State y cree una variable para mantener su condición (por ejemplo isButtonDisabled)
  • Establezca esto en verdadero inicialmente (si eso es lo que desea)
  • Al renderizar el botón, no establezca directamente elonPressed valor en ninguna nullfunción o en algunaonPressed: () {}
  • En su lugar , configúrelo condicionalmente usando una función ternaria o auxiliar (ejemplo a continuación)
  • Marque isButtonDisabledcomo parte de este condicional y devuelva nulluna función o alguna.
  • Cuando se presiona el botón (o siempre que desee deshabilitar el botón) use setState(() => isButtonDisabled = true)para invertir la variable condicional.
  • Flutter volverá a llamar al build()método con el nuevo estado y el botón se renderizará con un nullcontrolador de prensa y se desactivará.

Aquí hay más contexto usando el proyecto de contador Flutter.

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,
    );
  }
}

En este ejemplo, estoy usando un ternario en línea para establecer condicionalmente el Texty onPressed, pero puede ser más apropiado que extraiga esto en una función (puede usar este mismo método para cambiar el texto del botón también):

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();
      };
    }
  }
Ashton Thomas
fuente
3
Debe agregar la función de flecha gruesa como argumento; de lo contrario, se llamará a la función _incrementCounter () de inmediato cuando se habilite el botón. De esta manera, en realidad esperará hasta que se haga clic en el botón: el onPressed debería verse así:onPressed: _isButtonDisabled ? null : () => _incrementCounter
Vit Veres
2
@vitVeres que suele ser cierto, pero _counterButtonPress () está devolviendo una función, return () {}por lo que es intencional. No quiero usar la flecha gruesa aquí porque quiero que la función se ejecute y regrese nully desactive el botón.
Ashton Thomas
@AshtonThomas Sí, en el método extraído _counterButtonPress () es exactamente como lo explicó, pero estaba haciendo referencia al código con el operador ternario antes de que sugiriera la extracción. En su primer ejemplo, causará la ejecución del método _incrementCounter () cuando el botón debería estar habilitado. La próxima vez intentaré señalar lo que quiero decir con más precisión :)
Vit Veres
30
¿Qué tenía de malo usar una disabledpropiedad, equipo de Flutter? Esto simplemente no es intuitivo: - /
Curly
1
la forma correcta es con AbsorbPointer o IgnorePointer. Simplemente widget en lugar de lógica con la configuración de onPressed en nulo.
ejdrian313
93

Según los documentos:

"Si la devolución de llamada onPressed es nula, entonces el botón se desactivará y de forma predeterminada se parecerá a un botón plano en disabledColor".

https://docs.flutter.io/flutter/material/RaisedButton-class.html

Entonces, podrías hacer algo como esto:

    RaisedButton(
      onPressed: calculateWhetherDisabledReturnsBool() ? null : () => whatToDoOnPressed,
      child: Text('Button text')
    );
Steve Alexander
fuente
2
A juzgar por los documentos, así es como se implementará. Con las propiedades de respuesta aceptadas como disabledElevation, disabledColory DisabledTextColorno funcionará como se esperaba.
Joel Broström
Pff gracias por esto Steve, no planeaba revisar todo el código de la respuesta actualmente aceptada. @ chris84948, considere cambiar esto a la respuesta aceptada.
CularBytes
42

La respuesta simple es onPressed : nullun botón desactivado.

BINAY THAPA MAGAR
fuente
17

Ajuste

onPressed: null // disables click

y

onPressed: () => yourFunction() // enables click
CopsOnRoad
fuente
1
En esta solución, el valor de onPressedes siempre una función, por lo que el botón se representa como 'seleccionable', aunque ignorará el evento de clic si isEnabledse establece la propiedad. Para deshabilitar realmente el botón, useRaisedButton(onPressed: isEnabled ? _handleClick : null
Curly
15

Para un número específico y limitado de widgets, envolverlos en un widget IgnorePointer hace exactamente esto: cuando su ignoringpropiedad se establece en verdadera, no se puede hacer clic en el sub-widget (en realidad, todo el subárbol).

IgnorePointer(
    ignoring: true, // or false
    child: RaisedButton(
        onPressed: _logInWithFacebook,
        child: Text("Facebook sign-in"),
        ),
),

De lo contrario, si tiene la intención de deshabilitar un subárbol completo, busque en AbsorbPointer ().

Edmond
fuente
9

La funcionalidad de habilitar y deshabilitar es la misma para la mayoría de los widgets.

Ej. Botón, interruptor, casilla de verificación, etc.

Simplemente configure la onPressedpropiedad como se muestra a continuación

onPressed : nulldevuelve el widget deshabilitado

onPressed : (){}o onPressed : _functionNamedevuelve el widget habilitado

Vicky Salunkhe
fuente
6

También puede usar AbsorbPointer, y lo puede usar de la siguiente manera:

AbsorbPointer(
      absorbing: true, // by default is true
      child: RaisedButton(
        onPressed: (){
          print('pending to implement onPressed function');
        },
        child: Text("Button Click!!!"),
      ),
    ),

Si quieres saber más sobre este widget, puedes consultar el siguiente enlace Flutter Docs

Juanes30
fuente
2
Ignore- / AbsorbPointer no considera los estilos deshabilitados solo como un RECORDATORIO :-)
Pascal
4

Esta es la forma más fácil en mi opinión:

RaisedButton(
  child: Text("PRESS BUTTON"),
  onPressed: booleanCondition
    ? () => myTapCallback()
    : null
)
MatPag
fuente