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

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

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

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

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

Спасибо.

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

Seth Ladd 18.03.2018 22:21
5 дизайнов темных кнопок с использованием HTML и CSS
5 дизайнов темных кнопок с использованием HTML и CSS
Здесь представлены пять дизайнов темных кнопок с кодом с использованием HTML и CSS:
185
1
149 597
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Ответ принят как подходящий

Я думаю, вы можете захотеть ввести некоторые вспомогательные функции для вашей кнопки 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();
      };
    }
  }

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

Vit Veres 12.04.2018 07:21

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

Ashton Thomas 14.04.2018 16:34

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

Vit Veres 15.04.2018 17:55

Что было не так с использованием свойства disabled, команда Flutter? Это просто не интуитивно понятно: - /

SoftWyer 10.08.2019 18:19

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

ejdrian313 18.11.2019 14:16

Этого недостаточно, потому что он предполагает, что onPress: является синхронным кодом, хотя вполне возможно, что код является асинхронным и работоспособным, разделение кода каждой кнопки на несколько функций, чтобы обойти это, вызывает кошмар обслуживания

Raiden Core 02.07.2020 22:57

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

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

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

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

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

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

Joel Broström 11.02.2019 11:55

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

CularBytes 08.03.2020 13:49

Этот ответ должен быть принятым, подход проще, чем предполагалось в документации.

TheLetch 20.10.2020 23:28

да, но можно ли разрушить дом изнутри и все равно убежать? или вы можете обнулить onPress из setStatus внутри onPress?

none 27.10.2020 12:31

Простой ответ - onPressed : null дает отключенную кнопку.

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

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

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

как вы справляетесь с повреждением кода или ошибкой в ​​выполнении кода, чтобы избавиться от игнорирования?

none 27.10.2020 11:46

Параметр

onPressed: null // disables click

а также

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

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

SoftWyer 10.08.2019 18:42

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

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

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

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

Pascal 31.01.2020 22:54

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

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

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

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

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

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

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

Вы также можете установить пустое условие вместо установленного нуля

         var isDisable=true;

   

          RaisedButton(
              padding: const EdgeInsets.all(20),
              textColor: Colors.white,
              color: Colors.green,
              onPressed:  isDisable
                  ? () => (){} : myClickingData(),
              child: Text('Button'),
            )

Я люблю использовать для этого flutter_mobx и работаю над состоянием.

Далее я использую наблюдателя:

Container(child: Observer(builder: (_) {
  var method;
  if (!controller.isDisabledButton) method = controller.methodController;
  return RaiseButton(child: Text('Test') onPressed: method);
}));

На контроллере:

@observable
bool isDisabledButton = true;

Затем внутри элемента управления вы можете манипулировать этой переменной по своему усмотрению.

Ссылка: Флаттер мобкс

Для отключения любого Кнопка во флаттере, такого как FlatButton, RaisedButton, MaterialButton, IconButton и т. д., Все, что вам нужно сделать, это установить свойства onPressed и onLongPress на ноль. Ниже приведены несколько простых примеров некоторых кнопок:

FlatButton (включен)

FlatButton(
  onPressed: (){}, 
  onLongPress: null, // Set one as NOT null is enough to enable the button
  textColor: Colors.black,
  disabledColor: Colors.orange,
  disabledTextColor: Colors.white,
  child: Text('Flat Button'),
),

FlatButton (отключено)

FlatButton(
  onPressed: null,
  onLongPress: null,
  textColor: Colors.black,
  disabledColor: Colors.orange,
  disabledTextColor: Colors.white,
  child: Text('Flat Button'),
),

RaisedButton (включено)

RaisedButton(
  onPressed: (){},
  onLongPress: null, // Set one as NOT null is enough to enable the button
  // For when the button is enabled
  color: Colors.lightBlueAccent,
  textColor: Colors.black,
  splashColor: Colors.blue,
  elevation: 8.0,

  // For when the button is disabled
  disabledTextColor: Colors.white,
  disabledColor: Colors.orange,
  disabledElevation: 0.0,

  child: Text('Raised Button'),
),

RaisedButton (отключено)

RaisedButton(
  onPressed: null,
  onLongPress: null,
  // For when the button is enabled
  color: Colors.lightBlueAccent,
  textColor: Colors.black,
  splashColor: Colors.blue,
  elevation: 8.0,

  // For when the button is disabled
  disabledTextColor: Colors.white,
  disabledColor: Colors.orange,
  disabledElevation: 0.0,

  child: Text('Raised Button'),
),

IconButton (включен)

IconButton(
  onPressed: () {},
  icon: Icon(Icons.card_giftcard_rounded),
  color: Colors.lightBlueAccent,
            
  disabledColor: Colors.orange,
),

IconButton (отключено)

IconButton(
  onPressed: null,
  icon: Icon(Icons.card_giftcard_rounded),
  color: Colors.lightBlueAccent,
            
  disabledColor: Colors.orange,
),

Примечание: Некоторые кнопки, такие как IconButton, имеют только свойство onPressed.

Этот ответ основан на обновленных кнопках TextButton/ElevatedButtonOutlinedButton для Flutter 2.x

Тем не менее, кнопки по-прежнему включены или отключены в зависимости от свойства onPressed. Если это свойство равно null, кнопка будет отключена. Если вы назначите функцию onPressed, тогда кнопка будет активирована. В приведенных ниже фрагментах я показал, как включить / отключить кнопку и соответствующим образом обновить ее стиль.

This post also indicating that how to apply different styles to new Flutter 2.x buttons.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool textBtnswitchState = true;
  bool elevatedBtnSwitchState = true;
  bool outlinedBtnState = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                TextButton(
                  child: Text('Text Button'),
                  onPressed: textBtnswitchState ? () {} : null,
                  style: ButtonStyle(
                    foregroundColor: MaterialStateProperty.resolveWith(
                      (states) {
                        if (states.contains(MaterialState.disabled)) {
                          return Colors.grey;
                        } else {
                          return Colors.red;
                        }
                      },
                    ),
                  ),
                ),
                Column(
                  children: [
                    Text('Change State'),
                    Switch(
                      value: textBtnswitchState,
                      onChanged: (newState) {
                        setState(() {
                          textBtnswitchState = !textBtnswitchState;
                        });
                      },
                    ),
                  ],
                )
              ],
            ),
            Divider(),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                ElevatedButton(
                  child: Text('Text Button'),
                  onPressed: elevatedBtnSwitchState ? () {} : null,
                  style: ButtonStyle(
                    foregroundColor: MaterialStateProperty.resolveWith(
                      (states) {
                        if (states.contains(MaterialState.disabled)) {
                          return Colors.grey;
                        } else {
                          return Colors.white;
                        }
                      },
                    ),
                  ),
                ),
                Column(
                  children: [
                    Text('Change State'),
                    Switch(
                      value: elevatedBtnSwitchState,
                      onChanged: (newState) {
                        setState(() {
                          elevatedBtnSwitchState = !elevatedBtnSwitchState;
                        });
                      },
                    ),
                  ],
                )
              ],
            ),
            Divider(),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                OutlinedButton(
                  child: Text('Outlined Button'),
                  onPressed: outlinedBtnState ? () {} : null,
                  style: ButtonStyle(
                      foregroundColor: MaterialStateProperty.resolveWith(
                    (states) {
                      if (states.contains(MaterialState.disabled)) {
                        return Colors.grey;
                      } else {
                        return Colors.red;
                      }
                    },
                  ), side: MaterialStateProperty.resolveWith((states) {
                    if (states.contains(MaterialState.disabled)) {
                      return BorderSide(color: Colors.grey);
                    } else {
                      return BorderSide(color: Colors.red);
                    }
                  })),
                ),
                Column(
                  children: [
                    Text('Change State'),
                    Switch(
                      value: outlinedBtnState,
                      onChanged: (newState) {
                        setState(() {
                          outlinedBtnState = !outlinedBtnState;
                        });
                      },
                    ),
                  ],
                )
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Если вы ищете быстрый способ и не заботитесь о том, чтобы пользователь действительно нажимал кнопку более одного раза. Вы также можете сделать это следующим образом:

// Constant whether button is clicked
bool isClicked = false;

а затем проверяет в функции onPressed (), нажал ли пользователь кнопку уже или нет.

onPressed: () async {
    if (!isClicked) {
       isClicked = true;
       // await Your normal function
    } else {
       Toast.show(
          "You click already on this button", context,
          duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
    }
}

Другие вопросы по теме