Я только начинаю разбираться в Flutter, но у меня возникли проблемы с определением, как установить включенное состояние кнопки.

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

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

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

Спасибо.

chris84948

Ответов: 13

Ответы (13)

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

  • Используйте 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 {
  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: [
            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();
      };
    }
  }

Отключает клик:

onPressed: null

Включает щелчок:

onPressed: () => fooFunction() 
// or
onPressed: fooFunction

Комбинация:

onPressed: shouldEnable? fooFunction: нуль

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

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

For disabling any Button in flutter such as FlatButton, RaisedButton, MaterialButton, IconButton etc all you need to do is to set the onPressed and onLongPress properties to null. Below is some simple examples for some of the buttons:

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'),
),

enter image description here enter image description here

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

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

enter image description here

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'),
),

enter image description here

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'),
),

enter image description here

IconButton (включен)

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

enter image description here enter image description here

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

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

enter image description here

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

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

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

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

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

         var isDisable=true;

   

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

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

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

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

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

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

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

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

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

В этом сообщении также указывается, как применять разные стили к новым Кнопки Flutter 2.x.

enter image description here

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 {
  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: [
            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;
                        });
                      },
                    ),
                  ],
                )
              ],
            ),
          ],
        ),
      ),
    );
  }
}

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

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

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

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

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

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

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

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

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

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

Мне нравится использовать для этого 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;

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

Ссылка: Flutter mobx

2022 WebDevInsider