Как отключить кнопку во Flutter?


122

Я только начинаю осваивать Flutter, но мне сложно понять, как установить включенное состояние кнопки.

В документации говорится, что нужно установить onPressedзначение null, чтобы отключить кнопку, и присвоить ей значение, чтобы включить ее. Это нормально, если кнопка продолжает оставаться в том же состоянии в течение жизненного цикла.

У меня сложилось впечатление, что мне нужно создать настраиваемый виджет с отслеживанием состояния, который позволит мне каким-то образом обновить состояние включения кнопки (или обратный вызов onPressed).

Итак, мой вопрос: как мне это сделать? Это кажется довольно простым требованием, но в документации я не могу найти ничего о том, как это сделать.

Спасибо.


Не могли бы вы прояснить, что вы имеете в виду под словами «Это нормально, если кнопка продолжает оставаться в том же состоянии в течение всего жизненного цикла». ?
Сет Лэдд,

Ответы:


133

Я думаю, вы можете захотеть ввести некоторые вспомогательные функции для buildсвоей кнопки, а также виджет с отслеживанием состояния вместе с некоторым свойством, которое нужно отключить.

  • Используйте StatefulWidget / State и создайте переменную для хранения вашего состояния (например isButtonDisabled)
  • Изначально установите значение true (если вы этого хотите)
  • При рендеринге кнопки не устанавливайтеonPressed значение напрямую для nullкакой- либо функцииonPressed: () {}
  • Вместо этого условно установите его с помощью тернарной или вспомогательной функции (пример ниже)
  • Отметьте isButtonDisabledкак часть этого условного выражения и верните любую nullили некоторую функцию.
  • Когда кнопка нажата (или когда вы хотите отключить кнопку) используйте, setState(() => isButtonDisabled = true)чтобы перевернуть условную переменную.
  • Flutter снова вызовет build()метод с новым состоянием, и кнопка будет отрисована с помощью nullобработчика нажатия и будет отключена.

Вот еще несколько примеров использования счетчика 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,
    );
  }
}

В этом примере я использую встроенный троичный элемент для условной установки Textи onPressed, но может быть более подходящим для вас извлечь его в функцию (вы также можете использовать этот же метод для изменения текста кнопки):

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
Вам нужно добавить функцию жирной стрелки в качестве аргумента, иначе функция _incrementCounter () будет вызываться сразу же, когда кнопка станет активной. Таким образом, он фактически будет ждать, пока не будет нажата кнопка: onPressed должен выглядеть так:onPressed: _isButtonDisabled ? null : () => _incrementCounter
Вит Верес

2
@vitVeres, что обычно верно, но _counterButtonPress () возвращает функцию, return () {}поэтому это сделано намеренно. Я не хочу использовать здесь толстую стрелку, так как хочу, чтобы функция выполнялась, возвращалась nullи отключала кнопку.
Эштон Томас

@AshtonThomas Да, в извлеченном методе _counterButtonPress () это именно то, что вы объяснили, но я ссылался на код с тернарным оператором до того, как вы предложили извлечение. В вашем первом примере это вызовет выполнение метода _incrementCounter (), когда кнопка должна быть включена. В следующий раз попробую точнее указать, о чем я :)
Вит Верес

31
Что плохого в использовании disabledсобственности, команда Flutter? Это просто не интуитивно
Curly

1
правильный способ - с AbsorbPointer или IgnorePointer. Просто способ виджета вместо логики с настройкой onPressed на null.
ejdrian313

99

Согласно документам:

«Если обратный вызов onPressed имеет значение null, кнопка будет отключена и по умолчанию будет напоминать плоскую кнопку в disabledColor».

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

Итак, вы можете сделать что-то вроде этого:

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

2
Судя по документации, вот как это должно быть реализовано. С Принятая свойства ответа , как disabledElevation, disabledColorи DisabledTextColorне будет работать , как задумано.
Joel

Пфф, спасибо за это, Стив, не планировал просматривать весь код принятого в настоящее время ответа. @ chris84948, подумайте о том, чтобы изменить это на принятый ответ.
CularBytes


17

Настройка

onPressed: null // disables click

и

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

1
В этом решении значение onPressedвсегда является функцией, поэтому кнопка отображается как «интерактивная», хотя она будет игнорировать событие щелчка, если isEnabledсвойство установлено. Чтобы действительно отключить кнопку, используйтеRaisedButton(onPressed: isEnabled ? _handleClick : null
Curly

15

Для определенного и ограниченного числа виджетов их упаковка в виджет IgnorePointer делает именно это: когда его ignoringсвойство имеет значение true, суб-виджет (фактически, все поддерево) не доступен для нажатия .

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

В противном случае, если вы намереваетесь отключить все поддерево, посмотрите AbsorbPointer ().


9

Функциональные возможности включения и отключения одинаковы для большинства виджетов.

Например, кнопка, переключатель, флажок и т. Д.

Просто установите onPressedсвойство, как показано ниже

onPressed : nullвозвращает отключенный виджет

onPressed : (){}или onPressed : _functionNameвозвращает включенный виджет


7

Вы также можете использовать AbsorbPointer, и вы можете использовать его следующим образом:

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

Если вы хотите узнать больше об этом виджете, вы можете проверить следующую ссылку Flutter Docs


2
Ignore- / AbsorbPointer не рассматривает отключенные стили просто как НАПОМИНАНИЕ :-)
Паскаль

5

На мой взгляд, это самый простой способ:

RaisedButton(
  child: Text("PRESS BUTTON"),
  onPressed: booleanCondition
    ? () => myTapCallback()
    : null
)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.