【问题标题】:how to disable button after first click in flutter?第一次单击颤动后如何禁用按钮?
【发布时间】:2019-08-11 21:34:23
【问题描述】:

同时多次点击按钮,多次打开页面。如何解决这个问题?我还在我的应用程序上上传了 gif 文件(双击图片)。

     Container(
                            padding: EdgeInsets.all(10.0),
                            child: ButtonTheme(
                              minWidth: 10.0,
                              height: 40.0,
                              child: RaisedButton(
                                child: Text(
                                  AppTranslations.of(context)
                                      .text("loginpage_button"),
                                  style: TextStyle(
                                      color: Colors.white, fontSize: 15.0),
                                ),
                                onPressed: () async{
                                  (isOffline)
                                    ? _showSnackBar()
                                      : checking2(usernameController, context, _url);
                                },
                                color: Colors.blue,
                                padding: EdgeInsets.all(20.0),
                              ),
                            ),
margin: EdgeInsets.only(top: 0.0),

)

我使用了这个代码,它可以工作,但是用户输入的用户名不正确,用户不能点击第二个类型的按钮。这是我的代码。

onPressed: () async {
 if (_firstClick) {
_firstClick = false;
(isOffline)
? _showSnackBar()
: checking2(usernameController, context, _url);
}

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    您可以使用bool 变量来保存RaisedButton 的状态:

    首先创建变量a设置它的初始值:

      var _firstPress = true ;
    

    然后在 onPressed 函数中添加 _firstPress

                      Container(
                        padding: EdgeInsets.all(10.0),
                        child: ButtonTheme(
                          minWidth: 10.0,
                          height: 40.0,
                          child: RaisedButton(
                            child: Text(
                              AppTranslations.of(context)
                                  .text("loginpage_button"),
                              style: TextStyle(
                                  color: Colors.white, fontSize: 15.0),
                            ),
                            onPressed: () async{
                            // This is what you should add in your code
                            if(_firstPress){
                              _firstPress = false ;
                              (isOffline) ? _showSnackBar() :checking2(usernameController, context, _url);
                              }
                            },
                            color: Colors.blue,
                            padding: EdgeInsets.all(20.0),
                          ),
                        ),
    
                        margin: EdgeInsets.only(top: 0.0),
                        )
    

    这样您的onPressed 函数将只响应RaisedButton 的第一次点击。

    【讨论】:

    • 如果用户第一次输入错误的用户名,用户不能按第二次按钮?
    • 可以分享checking2 的内容吗?
    • 它检查用户名== null,其他验证兄弟
    • 如何使用login 按钮导航到另一个屏幕?
    • 使用 Navigator.push()
    【解决方案2】:

    这个问题在这里回答How do I disable a Button in Flutter?

    您只需要使用 statefulWidget 并创建一个变量来保存您的条件,并根据您的事件进行更改。您的按钮将根据您的变量值启用或禁用。

    假设你的变量的初始状态,isDisable = false,这意味着 - 你的按钮默认是启用的。并在第一次单击更改状态变量的值后 isDisable = true。

    【讨论】:

    • 如果用户第一次输入错误的用户名,用户不能按第二次按钮?
    • @BhanukaIsuru 然后使用类似这样的条件渲染您的按钮 - 如果 isDisalbe = false 并且用户名或密码不正确,则按钮将被启用。实际上,如果用户名和密码正确,用户应该转到另一个页面,那么您就不需要再显示登录页面了。我建议你写你的用例,并根据它设置条件。我认为这会有所帮助。
    【解决方案3】:

    你可以把它变成一个StatefulWidget,而不是直接使用RaisedButton。然后使用 ChangeNotifier 将其状态从启用更改为禁用和控制按钮按下功能。它还将帮助您在不同的地方重用它。这是一个例子,你怎么能做到这一点

    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          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> {
      final ValueNotifier<MyButtonState> _myButtonStateChangeNotifier =
      ValueNotifier(MyButtonState.enable);
    
      @override
      Widget build(BuildContext context) {
    
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: MyButton(
              buttonStateChangeNotifier: _myButtonStateChangeNotifier,
              onPressed: _onButtonPressed,
              text: "Click Me",
            ),
          ),
        );
      }
    
      _onButtonPressed() {
        print("Button Pressed");
        _myButtonStateChangeNotifier.value = MyButtonState.disable;
      }
    
    }
    
    enum MyButtonState {enable, disable}
    
    class MyButton extends StatefulWidget {
      final VoidCallback onPressed;
      final String text;
      final TextStyle textStyle;
      final ValueNotifier<MyButtonState> buttonStateChangeNotifier;
    
      MyButton({
        @required this.onPressed,
        this.text = "",
        this.textStyle,
        this.buttonStateChangeNotifier,
      });
    
      @override
      _MyButtonState createState() => _MyButtonState();
    }
    
    class _MyButtonState extends State<MyButton> {
      MyButtonState _myButtonState = MyButtonState.enable;
      @override
      void initState() {
        super.initState();
        if (widget.buttonStateChangeNotifier != null) {
          widget.buttonStateChangeNotifier.addListener(_handleButtonStateChange);
          _myButtonState = widget.buttonStateChangeNotifier.value;
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return RaisedButton(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.all(Radius.circular(4)),
          ),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(widget.text)
            ],
          ),
          onPressed: _myButtonState == MyButtonState.enable
              ? _handleOnPress
              : null,
        );
      }
    
      _handleButtonStateChange() {
        setState(() {
          _myButtonState = widget.buttonStateChangeNotifier.value;
        });
      }
    
      _handleOnPress() {
        if (_myButtonState == MyButtonState.enable) {
          widget.onPressed();
        }
      }
    }
    

    【讨论】:

      【解决方案4】:

      感谢上面的@Mazin Ibrahim's 建议,设置一个基本的bool 切换标志可以正常工作。

      此实现基于在回调级别处理启用/禁用逻辑,独立于小部件布局细节。

      bool _isButtonEnabled = true;
      
      MessageSql _messageSql = new MessageSql(); // DB helper class
      
      final TextEditingController eCtrl = new TextEditingController();
      
      _onSendMessage(String message) {
      
        if (! _isButtonEnabled) {
          return;
        }
      
        _isButtonEnabled = false;
      
        _messageSql.insert(message).then((resultId) {
          //  only update all if save is successful
          eCtrl.clear();
      
          AppUi.dismissKeyboard();
      
          _isButtonEnabled = true;
      
          Future.delayed(const Duration(milliseconds: 400), () {
            setState(() {});
          })
          .catchError((error, stackTrace) {
            print("outer: $error");
          });
      }
      

      【讨论】:

        【解决方案5】:

        创建一个bool 变量,当按下按钮时该变量为true(因此,初始值设置为false)。

        bool _clicked = false; 
        
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            body: RaisedButton(
              child: Text('Button'),
              onPressed: _clicked
                  ? null
                  : () {
                      setState(() => _clicked = true); // set it to true now
                    },
            ),
          );
        }
        

        【讨论】:

          【解决方案6】:

          我为自己编写了两个可能对其他人有帮助的课程。他们将其他人给出的答案封装在这个线程中,这样你就不会到处乱跑一堆布尔和赋值语句。

          您将函数传递给类,并使用类的“调用”方法代替函数。这目前不支持需要参数的函数,但对于 void 情况很有用。

          typedef void CallOnceFunction();
          class CallOnce {
            bool _inFunction = false;
          
            final CallOnceFunction function;
          
            CallOnce(CallOnceFunction function) :
              assert(function != null),
              function = function
            ;
          
            void invoke() {
              if (_inFunction)
                return;
          
              _inFunction = true;
              function();
              _inFunction = false;
            }
          }
          
          typedef Future<void> CallOnceFuture();
          class CallFutureOnce {
            bool _inFunction = false;
          
            final CallOnceFuture future;
          
            CallFutureOnce(CallOnceFuture future) :
              assert(future != null),
              future = future
            ;
          
            Future<void> invoke() async {
              if (_inFunction)
                return;
          
              _inFunction = true;
              await this.future();
              _inFunction = false;
            }
          }
          

          更新:这是这两个类的实际示例

          /*Example*/
          import 'package:flutter/material.dart';
          
          class MyWidget extends StatefulWidget {
            @override
            State<StatefulWidget> createState() {
              return new MyWidgetState();
            }
          }
          
          class MyWidgetState extends State<MyWidget> {
          
            CallOnce _callOnce;
            CallFutureOnce _callFutureOnce;
          
            void myFunction() {
              /*Custom Code*/
            }
          
            Future<void> myFutureFunction() async {
              /*Custom Code*/
              //await something()
            }
          
            @override
            void initState() {
              super.initState();
          
              this._callOnce = CallOnce(this.myFunction);
              this._callFutureOnce = CallFutureOnce(this.myFutureFunction);
            }
          
            @override
            Widget build(BuildContext context) {
          
              return Scaffold (
                body: Center (
                  child: RaisedButton (
                    child: Text('Try Me'),
                    onPressed: this._callOnce.invoke,
                  ),
                ),
                floatingActionButton: FloatingActionButton (
                  child: Icon(Icons.save),
                  onPressed: this._callFutureOnce.invoke,
                ),
              );
            }
          }
          

          【讨论】:

          • 你能给我们展示一个如何使用这些类的例子吗?
          • @Djanko 当然,我已经更新了答案,显示了一个简单的例子
          【解决方案7】:

          根据计算时间差在我的应用程序中解决了这个问题。

          首先,声明一个DateTime变量,定义函数如下:-

          DateTime loginClickTime;
          
          bool isRedundentClick(DateTime currentTime){
          if(loginClickTime==null){
            loginClickTime = currentTime;
            print("first click");
            return false;
          }
          print('diff is ${currentTime.difference(loginClickTime).inSeconds}');
          if(currentTime.difference(loginClickTime).inSeconds<10){//set this difference time in seconds
            return true;
          }
          
          loginClickTime = currentTime;
          return false;
          }
          

          在登录按钮中调用如下函数来检查冗余:-

          RaisedButton(
                  child:Text('Login'),
                  onPressed: (){
                    if(isRedundentClick(DateTime.now())){
                      print('hold on, processing');
                      return;
                    }
                    print('run process');
                    },
                )
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-09-23
            • 2019-07-22
            • 1970-01-01
            • 1970-01-01
            • 2023-03-21
            • 2017-01-16
            相关资源
            最近更新 更多