Como desativo um botão no Flutter?


115

Estou apenas começando a pegar o jeito do Flutter, mas estou tendo problemas para descobrir como definir o estado ativado de um botão.

Nos documentos, ele diz para definir onPressedcomo nulo para desativar um botão e dar a ele um valor para ativá-lo. Isso é bom se o botão continuar no mesmo estado durante o ciclo de vida.

Tenho a impressão de que preciso criar um widget Stateful personalizado que me permitirá atualizar o estado ativado do botão (ou retorno de chamada onPressed) de alguma forma.

Então, minha pergunta é como eu faria isso? Parece um requisito bastante simples, mas não consigo encontrar nada nos documentos sobre como fazer isso.

Obrigado.


Você pode esclarecer o que quer dizer com "Tudo bem se o botão continuar no mesmo estado durante o ciclo de vida". ?
— Seth Ladd

Respostas:


127

Acho que você pode querer introduzir algumas funções auxiliares em buildseu botão, bem como um widget Stateful junto com algumas propriedades para desligar.

  • Use um StatefulWidget / State e crie uma variável para manter sua condição (por exemplo isButtonDisabled)
  • Defina isso como verdadeiro inicialmente (se for o que você deseja)
  • Ao renderizar o botão, não defina diretamente oonPressed valor para uma nullou outra funçãoonPressed: () {}
  • Em vez disso , defina-o condicionalmente usando uma função ternária ou auxiliar (exemplo abaixo)
  • Verifique o isButtonDisabledcomo parte desta condição e retorne uma nullou alguma função.
  • Quando o botão é pressionado (ou sempre que você deseja desabilitar o botão), use setState(() => isButtonDisabled = true)para inverter a variável condicional.
  • Flutter irá chamar o build()método novamente com o novo estado e o botão será renderizado com um nullmanipulador de pressão e desabilitado.

Aqui está um pouco mais de contexto usando o projeto Contador de oscilação.

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

Neste exemplo, estou usando um ternário in-line para definir condicionalmente o Texte onPressed, mas pode ser mais apropriado para você extrair isso em uma função (você pode usar o mesmo método para alterar o texto do botão também):

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

3
Você precisa adicionar a função seta grande como um argumento, caso contrário, a função _incrementCounter () será chamada imediatamente quando o botão for habilitado. Dessa forma, ele realmente aguardará até que o botão seja clicado: O onPressed deve ser semelhante a:onPressed: _isButtonDisabled ? null : () => _incrementCounter
— Vit Veres

2
@vitVeres isso geralmente é verdade, mas o _counterButtonPress () está retornando uma função, return () {}então isso é intencional. Não quero usar a seta grande aqui, pois quero que a função seja executada e retorne nulle desative o botão.
— Ashton Thomas de

@AshtonThomas Sim, no método extraído _counterButtonPress () é exatamente como você explicou, mas eu estava me referindo ao código com o operador ternário antes de você sugerir a extração. Em seu primeiro exemplo, isso causará a execução do método _incrementCounter () quando o botão deve ser habilitado. Da próxima vez, tentarei apontar o que quero dizer com mais precisão :)
— Vit Veres

30
O que havia de errado em usar uma disabledpropriedade, equipe Flutter? Isso não é intuitivo: - /
— Curly

1
a maneira correta é com AbsorbPointer ou IgnorePointer. Simplesmente forma de widget em vez de lógica com a configuração de onPressed para null.
— ejdrian313

93

De acordo com a documentação:

"Se o retorno de chamada onPressed for nulo, o botão será desativado e, por padrão, se parecerá com um botão plano na disabledColor."

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

Então, você pode fazer algo assim:

    RaisedButton(
      onPressed: calculateWhetherDisabledReturnsBool() ? null : () => whatToDoOnPressed,
      child: Text('Button text')
    );

2
A julgar pelos documentos, é assim que ele deve ser implementado. Com as propriedades de resposta aceitas como disabledElevation, disabledColore DisabledTextColornão funcionará como esperado.
— Joel Broström

Pff obrigado por isso Steve, não estava planejando passar por todo o código da resposta aceita atualmente. @ chris84948, considere mudar para a resposta aceita.
— CularBytes


17

Configuração

onPressed: null // disables click

e

onPressed: () => yourFunction() // enables click

1
Nesta solução, o valor de onPressedé sempre uma função, então o botão é renderizado como 'clicável', embora ele ignore o evento de clique se a isEnabledpropriedade for definida. Para realmente desabilitar o botão, useRaisedButton(onPressed: isEnabled ? _handleClick : null
— Curly

15

Para um número específico e limitado de widgets, envolvê-los em um widget IgnorePointer faz exatamente isso: quando sua ignoringpropriedade é definida como true, o sub-widget (na verdade, a subárvore inteira) não é clicável.

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

Caso contrário, se você pretende desabilitar uma subárvore inteira, procure em AbsorbPointer ().


9

A funcionalidade Habilitar e Desabilitar é a mesma para a maioria dos widgets.

Ex: botão, interruptor, caixa de seleção etc.

Basta definir a onPressedpropriedade conforme mostrado abaixo

onPressed : nullretorna widget desativado

onPressed : (){}ou onPressed : _functionNameretorna widget Ativado


6

Você também pode usar o AbsorbPointer da seguinte maneira:

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

Se você quiser saber mais sobre este widget, você pode verificar o seguinte link Flutter Docs


2
Ignore- / AbsorbPointer não considera os estilos desativados apenas como um LEMBRETE :-)
— Pascal

4

Esta é a maneira mais fácil na minha opinião:

RaisedButton(
  child: Text("PRESS BUTTON"),
  onPressed: booleanCondition
    ? () => myTapCallback()
    : null
)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.