如何在Flutter中禁用按钮?

时间:2018-03-18 18:50:09

标签: button dart flutter

我刚刚开始了解Flutter,但我无法弄清楚如何设置按钮的启用状态。

从文档中,它说要将onPressed设置为null以禁用按钮,并为其设置一个值以启用它。如果按钮在生命周期中继续处于相同状态,则此功能正常。

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

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

感谢。

13 个答案:

答案 0 :(得分:48)

我想你可能想要向你的按钮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,
    );
  }
}

在这个示例中,我使用内联三元来有条件地设置TextonPressed,但是将它提取到函数中可能更合适(可以使用相同的方法也改变按钮的文字):

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

答案 1 :(得分:26)

根据文档:

“如果onPressed回调为null,则该按钮将被禁用,并且默认情况下将类似于DisabledColor中的平面按钮。”

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

因此,您可能会执行以下操作:

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

答案 2 :(得分:12)

简单的答案是ie. this exclude filter: "//sourcedir//a//////file2" becomes this: "/sourcedir/a/file2" diff --git a/exclude.c b/exclude.c index a0090b29..e3a1b089 100644 --- a/exclude.c +++ b/exclude.c @@ -772,7 +772,9 @@ int check_filter(filter_rule_list *listp, enum logcode code, if (rule_matches(name, ent, name_flags)) { report_filter_result(code, name, ent, name_flags, listp->debug_type); return ent->rflags & FILTRULE_INCLUDE ? 1 : -1; - } +// }else{ +// report_filter_result(code, name, ent, name_flags, listp->debug_type); + } } return 0; @@ -805,7 +807,9 @@ static const uchar *rule_strcmp(const uchar *str, const char *rule, int rule_len * template rflags and the xflags additionally affect parsing. */ static filter_rule *parse_rule_tok(const char **rulestr_ptr, const filter_rule *template, int xflags, - const char **pat_ptr, unsigned int *pat_len_ptr) + //const char **pat_ptr, + char **pat_ptr, + unsigned int *pat_len_ptr) { const uchar *s = (const uchar *)*rulestr_ptr; filter_rule *rule; @@ -1045,7 +1049,8 @@ static filter_rule *parse_rule_tok(const char **rulestr_ptr, && !(rule->rflags & (FILTRULES_SIDES|FILTRULE_MERGE_FILE|FILTRULE_PERDIR_MERGE))) rule->rflags |= FILTRULE_SENDER_SIDE; - *pat_ptr = (const char *)s; + //*pat_ptr = (const char *)s; + *pat_ptr = (char *)s; *pat_len_ptr = len; *rulestr_ptr = *pat_ptr + len; return rule; @@ -1092,7 +1097,8 @@ void parse_filter_str(filter_rule_list *listp, const char *rulestr, const filter_rule *template, int xflags) { filter_rule *rule; - const char *pat; + //const char *pat; + char *pat; unsigned int pat_len; if (!rulestr) @@ -1105,6 +1111,25 @@ void parse_filter_str(filter_rule_list *listp, const char *rulestr, if (!(rule = parse_rule_tok(&rulestr, template, xflags, &pat, &pat_len))) break; + rprintf(FERROR, "!! got filter(len=%d): %.*s\n", //FIXME: the filter pattern here has the adjacent slashes! but it's a pointer not malloc-ed! so not sure if I should modify it? hmm + (int)pat_len,(int)pat_len, pat); + + if (pat_len>1) { + unsigned int curpos=1; + for (unsigned int i=1; i<pat_len; i++) { + if (('/' == pat[i-1]) && ('/' == pat[i])) { //FIXME: is string containing 1 char-wide chars? or is it i dno, utf-8/unicode or whatnot? in other words, is a char 1 byte long? is '/' 1 byte long? because the 1 and ++ assume so! + continue; + } else { + pat[curpos]=pat[i]; + curpos++; + } + } + if (curpos <pat_len) { + pat_len=curpos;//curpos is already +1 btw! due to curpos++ above + rprintf(FERROR, "!! fixed filter(len=%d): %.*s\n", + (int)pat_len,(int)pat_len, pat); + } + } if (pat_len >= MAXPATHLEN) { rprintf(FERROR, "discarding over-long filter: %.*s\n", (int)pat_len, pat); 给出了一个禁用的按钮。

答案 3 :(得分:11)

我认为这是最简单的方法:

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

答案 4 :(得分:6)

要禁用颤动中的任何 按钮,例如 FlatButtonRaisedButtonMaterialButtonIconButton 等,您需要做的就是设置onPressedonLongPress 属性为 null。下面是一些按钮的简单示例:

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(
  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(
  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(
  onPressed: () {},
  icon: Icon(Icons.card_giftcard_rounded),
  color: Colors.lightBlueAccent,
            
  disabledColor: Colors.orange,
),

enter image description here enter image description here

图标按钮(已禁用)

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

enter image description here

注意:某些按钮(例如 IconButton)只有 onPressed 属性。

答案 5 :(得分:6)

此答案基于 TextButton/ElevatedButtonOutlinedButton 的更新按钮 Flutter 2.x

仍然根据 onPressed 属性启用或禁用按钮。如果该属性为空,则按钮将被禁用。如果您将功能分配给 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<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;
                        });
                      },
                    ),
                  ],
                )
              ],
            ),
          ],
        ),
      ),
    );
  }
}

答案 6 :(得分:5)

对于特定数量和数量有限的小部件,将它们包装在小部件IgnorePointer中可以做到这一点:当其ignoring属性设置为true时,子小部件(实际上是整个子树)是不可点击的。

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

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

答案 7 :(得分:1)

您可以启用或禁用此类按钮

RaisedButton(onPressed: () => isEnabled ? _handleClick : null) 

答案 8 :(得分:1)

您还可以使用AbsorbPointer,并且可以通过以下方式使用它:

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

如果您想进一步了解此小部件,可以查看以下链接Flutter Docs

答案 9 :(得分:0)

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

Ex,按钮,开关,复选框等

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

onPressed : null返回已禁用的小部件

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

答案 10 :(得分:0)

您还可以设置空白条件,代替设置null

         var isDisable=true;

   

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

答案 11 :(得分:-1)

如果您正在寻找一种快速的方法,并且不关心让用户实际点击一个按钮一次。您也可以通过以下方式进行操作:

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

答案 12 :(得分:-2)

我喜欢为此使用 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