动画期间按钮宽度不变

时间:2019-07-06 02:12:38

标签: flutter dart flutter-animation

我正在尝试实现按钮动画,在单击时它会缩小并显示圆形进度指示器(在加载时),然后展开并显示已执行操作的结果(在本例中为登录)。

代码思想来自此link。设计思想来自这个link。现在,我以前实现了它,并且它按预期的方式工作。但是,当在此处再次实现该功能时,按下按钮->人员将成功登录,并且按钮将根据设计全部更改颜色。唯一的问题是按钮动画不会发生。我尝试打印_loginButtonWidth的值,实际上可以看到它按照设计逐渐减小和增大,但是在视觉上宽度保持不变。

代码:

import 'package:flutter/material.dart';
import 'package:garuda_academy_app/Login/Authentication.dart';
import 'package:garuda_academy_app/Tools/FixedColors.dart';
import 'dart:async';

class LoginPage extends StatefulWidget {
  LoginPage({this.auth, this.onLoggedIn});

  @override
  _LoginPageState createState() => _LoginPageState();

  final BaseAuth auth;
  final VoidCallback onLoggedIn;
}

class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
  // for device type
  bool _isIos;

  // text form field
  String _userEmail = "";
  String _userPassword = "";
  final _formKey = GlobalKey<FormState>();

  // for login button
  int _loginButtonState = 0;
  double _loginButtonWidth = double.maxFinite;
  Color _loginButtonColor = primaryColor;
  Color _loginButtonOutlineColor = primaryColor;
  Color _loginButtonTextColor = secondaryColor;
  GlobalKey _loginButtonKey = GlobalKey();
  Animation _loginButtonAnimation;
  AnimationController _loginButtonController;

  Widget _loginButton() {
    if (_loginButtonState == 0) {
      return Text(
        "Log In",
        style: TextStyle(
          color: _loginButtonTextColor,
          fontSize: 20,
        ),
      );
    } else if (_loginButtonState == 1) {
      return CircularProgressIndicator(
        valueColor: AlwaysStoppedAnimation<Color>(secondaryColor),
      );
    } else if (_loginButtonState == 2) {
      return Icon(
        Icons.check,
        color: _loginButtonTextColor,
      );
    } else if (_loginButtonState == 3) {
      return Icon(
        Icons.close,
        color: _loginButtonTextColor,
      );
    } else if (_loginButtonState == 4) {
      return Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Icon(
            Icons.check,
            color: _loginButtonTextColor,
          ),
          Icon(
            Icons.check,
            color: transparent,
          ),
          Text(
            "Successful",
            style: TextStyle(
              color: _loginButtonTextColor,
            ),
          ),
        ],
      );
    } else if (_loginButtonState == 5) {
      return Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Icon(
            Icons.close,
            color: _loginButtonTextColor,
          ),
          Icon(
            Icons.close,
            color: transparent,
          ),
          Text(
            "Unsuccessful",
            style: TextStyle(
              color: _loginButtonTextColor,
            ),
          ),
        ],
      );
    }
  }

  bool _validateLoginAndSave() {
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      return true;
    }
    return false;
  }

  _animateLoginButton() async {
    String userId = "";
    String errorMsg = "";
    setState(() {
      _loginButtonState = 1;
    });
    // animation
    double initialWidth = _loginButtonKey.currentContext.size.width;
    _loginButtonController =
        AnimationController(duration: Duration(milliseconds: 300), vsync: this)
          ..addStatusListener((AnimationStatus status) async {
            if (status == AnimationStatus.completed) {
              // firebase signin
              try {
                userId = await widget.auth.signIn(_userEmail, _userPassword);
              } catch (e) {
                setState(() {
                  errorMsg = _isIos ? e.details : e.message;
                  print(errorMsg);
                });
              }

              // loading timer
              Timer(Duration(seconds: 1), () {
                // set login state
                _loginButtonState =
                    (userId.length > 0 && userId != null) ? 2 : 3;
                // change colors
                if (_loginButtonState == 2) {
                  _loginButtonColor = secondaryColor;
                  _loginButtonOutlineColor = successfulColor;
                  _loginButtonTextColor = successfulColor;
                } else if (_loginButtonState == 3) {
                  _loginButtonColor = secondaryColor;
                  _loginButtonOutlineColor = unsuccessfulColor;
                  _loginButtonTextColor = unsuccessfulColor;
                }
                _loginButtonController.reverse();
              });
            } else if (status == AnimationStatus.dismissed) {
              if (_loginButtonState == 2) {
                _loginButtonState = 4;
              } else if (_loginButtonState == 3) {
                _loginButtonState = 5;
              }
              // minimal time before it is done
              Timer(Duration(seconds: 1), () {
                setState(() {
                  if (_loginButtonState == 4) widget.onLoggedIn();
                  // reset state
                  _loginButtonState = 0;

                  // reset colors
                  _loginButtonColor = primaryColor;
                  _loginButtonOutlineColor = primaryColor;
                  _loginButtonTextColor = secondaryColor;
                });
              });
            }
          });

    _loginButtonAnimation =
        Tween(begin: 0.0, end: 1.0).animate(_loginButtonController)
          ..addListener(() {
            setState(() {
              _loginButtonWidth = initialWidth -
                  ((initialWidth - 80.0) * _loginButtonAnimation.value);
            });
            print("initial: " + initialWidth.toString());
            print("current: " + _loginButtonWidth.toString());
          });

    _loginButtonController.forward();
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    _isIos = Theme.of(context).platform == TargetPlatform.iOS;
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: SingleChildScrollView(
        child: Center(
          child: Theme(
            data: ThemeData(primaryColor: primaryColor),
            child: Form(
              key: _formKey,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>[
                  Padding(
                    padding: EdgeInsets.all(40),
                    child: Text(
                      "Log in to continue",
                      textAlign: TextAlign.left,
                      style: TextStyle(
                        fontSize: 30,
                        fontWeight: FontWeight.bold,
                        color: primaryColor,
                      ),
                    ),
                  ),
                  Padding(
                    padding: EdgeInsets.only(bottom: 20, left: 40, right: 40),
                    child: TextFormField(
                      keyboardType: TextInputType.emailAddress,
                      style: TextStyle(
                        fontSize: 20,
                      ),
                      decoration: InputDecoration(
                        labelText: "Email Address",
                        labelStyle: TextStyle(fontSize: 20),
                      ),
                      validator: (value) =>
                          value.isEmpty ? "Email cannot be empty" : null,
                      onSaved: (value) => _userEmail = value,
                    ),
                  ),
                  Padding(
                    padding: EdgeInsets.only(bottom: 20, left: 40, right: 40),
                    child: TextFormField(
                      keyboardType: TextInputType.emailAddress,
                      obscureText: true,
                      style: TextStyle(
                        fontSize: 20,
                      ),
                      decoration: InputDecoration(
                        labelText: "Password",
                        labelStyle: TextStyle(fontSize: 20),
                      ),
                      validator: (value) =>
                          value.isEmpty ? "Password cannot be empty" : null,
                      onSaved: (value) => _userPassword = value,
                    ),
                  ),
                  Padding(
                    padding: EdgeInsets.only(bottom: 50, left: 40, right: 40),
                    child: Container(
                      height: 60,
                      width: _loginButtonWidth,
                      child: PhysicalModel(
                        color: transparent,
                        borderRadius: BorderRadius.circular(10.0),
                        child: RaisedButton(
                          elevation: 8.0,
                          color: _loginButtonColor,
                          key: _loginButtonKey,
                          shape: OutlineInputBorder(
                            borderSide: BorderSide(
                              color: _loginButtonOutlineColor,
                            ),
                            borderRadius: BorderRadius.circular(10.0),
                          ),
                          child: _loginButton(),
                          onPressed: () {
                            setState(() {
                              if (_loginButtonState == 0 &&
                                  _validateLoginAndSave()) {
                                _animateLoginButton();
                              }
                            });
                          },
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

应该缩小时按钮的宽度保持不变:

enter image description here

1 个答案:

答案 0 :(得分:2)

轻松修复,将CenterAlign小部件添加为Container按钮的父级。

 Padding(
                    padding: EdgeInsets.only(bottom: 50, left: 40, right: 40),
                    child: Center(
                      child: Container(
                        height: 60,
                        width: _loginButtonWidth,

要获取更多信息,请检查Layout Behavior