我刚开始掌握Flutter的窍门,但我不知道如何设置按钮的启用状态。

从文档中,它说将onPressed设置为null来禁用按钮,并给它一个值来启用它。如果按钮在生命周期中继续处于相同的状态,这是没问题的。

我得到的印象是,我需要创建一个自定义的有状态小部件,它将允许我以某种方式更新按钮的启用状态(或onPressed回调)。

我的问题是我该怎么做?这似乎是一个非常简单的要求,但我在文档中找不到任何关于如何做到这一点的东西。

谢谢。


我认为您可能需要引入一些帮助函数来构建按钮,以及一个有状态的小部件以及一些要关闭的属性。

Use a StatefulWidget/State and create a variable to hold your condition (e.g. isButtonDisabled) Set this to true initially (if that's what you desire) When rendering the button, don't directly set the onPressed value to either null or some function onPressed: () {} Instead, conditionally set it using a ternary or a helper function (example below) Check the isButtonDisabled as part of this conditional and return either null or some function. When the button is pressed (or whenever you want to disable the button) use setState(() => isButtonDisabled = true) to flip the conditional variable. Flutter will call the build() method again with the new state and the button will be rendered with a null press handler and be disabled.

这里是一些更多的上下文使用颤振计数器项目。

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

根据文件:

如果onPressed回调为空,则该按钮将被禁用 默认情况下类似于disabledColor中的平面按钮。

所以,你可以这样做:

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

简单的答案是onPressed: null给出一个禁用按钮。


对于特定且数量有限的小部件,将它们包装在小部件IgnorePointer中正是这样做的:当它的忽略属性被设置为true时,子小部件(实际上是整个子树)是不可点击的。

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

否则,如果您打算禁用整个子树,请查看AbsorbPointer()。


禁用点击:

onPressed: null

可以点击:

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

组合:

onPressed: shouldEnable ? fooFunction : null

你也可以使用吸收指针,你可以用下面的方式使用它:

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

如果您想了解有关此小部件的更多信息,可以查看以下链接Flutter Docs


大多数小部件的启用和禁用功能是相同的。

前,按钮,开关,复选框等。

只需设置onPressed属性,如下所示

onPressed: null返回禁用小部件

onPressed:(){}或onPressed: _functionName返回启用的小部件


在我看来,这是最简单的方法:

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

你也可以设置空白条件,在设置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;

然后在控件中,您可以随心所欲地操作这个变量。

参考文献。: Flutter mobx


为了禁用任何按钮,如FlatButton, RaisedButton, MaterialButton, IconButton等,你需要做的就是将onPressed和onLongPress属性设置为null。下面是一些按钮的简单示例:

FlatButton (Enabled)

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 (Enabled)

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/ElevatedButton/OutlinedButton颤振2.x

不过,按钮是基于onPressed属性启用或禁用的。如果该属性为空,则按钮将被禁用。如果你将函数分配给onPressed,那么按钮将被启用。 在下面的代码片段中,我展示了如何启用/禁用按钮,并相应地更新它的样式。

这篇文章也说明了如何将不同的风格应用到新的 颤振2。x按钮。

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

这是在Flutter中禁用按钮的最简单的方法是将空值分配给onPressed

ElevatedButton(
  style: ElevatedButton.styleFrom(
    primary: Colors.blue, // background
    onPrimary: Colors.white, // foreground
  ),
  onPressed: null,
  child: Text('ElevatedButton'),
),

见下面的可能的解决方案,添加'ValueListenableBuilder'的'TextEditingValue'监听控制器(TextEditingController),并返回你的函数调用如果控制器。文本不为空,如果为空则返回'null'。

// valuelistenablebuilder环绕按钮

  ValueListenableBuilder<TextEditingValue>(
                  valueListenable: textFieldController,
                  builder: (context, ctrl, __) => ElevatedButton(                    
                    onPressed: ctrl.text.isNotEmpty ? yourFunctionCall : null,
                    child: Text(
                      'SUBMIT',
                      style: GoogleFonts.roboto(fontSize: 20.0),
                    ),
                  ),
                ),

特克斯菲尔德

 TextField(controller: textFieldController,
                 onChanged: (newValue) {
                  textFieldText = newValue;
                },
              ),

生成器将监听控制器,并仅在使用文本字段时启用按钮。我希望这能回答问题。让我知道…


有两种方法:

1- https://stackoverflow.com/a/49354576/5499531

2-你可以使用MaterialStatesController:

final _statesController = MaterialStatesController();

然后将状态更改为:

_statesController.update(
   MaterialState.disabled,
   true, // or false depending on your logic
);

在你的按钮上

ElevatedButton(
    onPressed: _onPressed,
    statesController: _statesController,
    child: Text("Awesome"),
),

此外,你可以改变按钮的风格,当禁用: 在主题设置中:

....
elevatedButtonTheme: ElevatedButtonThemeData(
              style: ElevatedButton.styleFrom(
                backgroundColor: colors.primary500, // set your own color
                textStyle: button, // set your own style
                onPrimary: colors.onPrimary100, // set your own color
                enableFeedback: true,
                disabledBackgroundColor: colors.primary300, // set your own color
                disabledForegroundColor: colors.primary300, // set your own color
                disabledMouseCursor: SystemMouseCursors.forbidden, // when is disable the change the cursor type
              ),
            ),
...