【问题标题】:Flutter replace widget with SlideTransitionFlutter 用 SlideTransition 替换小部件
【发布时间】:2021-10-28 09:46:01
【问题描述】:

我想从右侧滑出我的第一个小部件,然后从屏幕左侧滑入第二个。

我正在尝试将AnimatedSwitcherSlideTransition 一起使用

我当前的代码错误是第一个小部件没有滑出,只是消失了

这是我的完整代码 sn-p。 任何帮助都会得到帮助


class LoginPage extends StatefulWidget {
  LoginPage({Key? key}) : super(key: key);

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

class _LoginPageState extends State<LoginPage>
    with SingleTickerProviderStateMixin {
  static const int PIN_CODE_LENGTH = 4;
  final TextEditingController _mobileController = TextEditingController();
  final TextEditingController _pinController = TextEditingController();
  final UniqueKey _mobileKey = UniqueKey();
  final UniqueKey _pinKey = UniqueKey();

  bool _submittable = false;
  bool _isLoginStepOne = true;
  String _buttonText = Strings.next;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Directionality(
        textDirection: TextDirection.rtl,
        child: SingleChildScrollView(
          child: SizedBox(
            height: SizePercentConfig.screenHeight,
            child: Column(
              children: [
                _buildHeader(),
                Expanded(
                  child: _buildForm(),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildHeader() {
    return Container(
      height: SizePercentConfig.safeBlockVertical * 60,
      child: Stack(
        children: [
          Positioned(
            bottom: 0,
            right: SizePercentConfig.blockSizeHorizontal * 30,
            left: SizePercentConfig.blockSizeHorizontal * 30,
            child: Image.asset(
              Assets.logo,
              fit: BoxFit.fitWidth,
            ),
          ),
          Container(
            height: SizePercentConfig.safeBlockVertical * 50,
            child: Stack(
              children: [
                Positioned(
                  bottom: 0,
                  child: Image.asset(
                    Assets.loginHeader,
                    width: SizePercentConfig.screenWidth,
                    fit: BoxFit.fitWidth,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildForm() {
    return Form(
      onChanged: _validate,
      child: Padding(
        padding: const EdgeInsets.all(Dimens.unitX2),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            AnimatedSwitcher(
                duration: const Duration(seconds: 1),
                transitionBuilder: (Widget child, Animation<double> animation) {
                  final inAnimation = Tween<Offset>(
                          begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0))
                      .animate(animation);
                  final outAnimation = Tween<Offset>(
                          begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0))
                      .animate(animation);

                  print('** child key: ${child.key}');
                  print('** mobile key: $_mobileKey');
                  print('** pin key: $_pinKey');
                  if (child.key == _mobileKey) {
                    // in animation
                    print('>>>>>>> first statement');
                    return ClipRect(
                      child: SlideTransition(
                        position: inAnimation,
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: child,
                        ),
                      ),
                    );
                  } else {
                    // out animation
                    print('>>>>>>> second statement');
                    return ClipRect(
                      child: SlideTransition(
                        position: outAnimation,
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: child,
                        ),
                      ),
                    );
                  }
                },
                layoutBuilder:
                    (Widget? currentChild, List<Widget> previousChildren) {
                  return currentChild!;
                },
                child: _isLoginStepOne
                    ? AppTextField(
                        key: _mobileKey,
                        controller: _mobileController,
                        hint: Strings.mobileNumber,
                        textInputType: TextInputType.phone,
                      )
                    : _buildPinCode()),
            SizedBox(height: Dimens.unitX2),
            AppSolidButton(
              onPressed: _buttonAction,
              text: _buttonText,
              width: SizePercentConfig.screenWidth,
              enabled: _submittable,
            ),
            SizedBox(height: Dimens.unitX2),
          ],
        ),
      ),
    );
  }

  void _validate() {
    if (_isLoginStepOne) {
      if (Regex.mobileRegex.hasMatch(_mobileController.value.text) !=
          _submittable)
        setState(() {
          print('--> setState called in _validate');
          _submittable = !_submittable;
        });
    } else {
      if ((_pinController.value.text.length == 4) != _submittable)
        setState(() {
          print('--> setState called in _validate');
          _submittable = !_submittable;
        });
    }
  }

  void _buttonAction() {
    if (_submittable) {
      setState(() {
        print('--> setState called in _buttonPressed');
        _isLoginStepOne = false;
        _submittable = false;
        _buttonText = Strings.login;
      });
    } else {}
  }

  Widget _buildPinCode() {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: PinCodeTextField(
        key: _pinKey,
        controller: _pinController,
        appContext: context,
        length: PIN_CODE_LENGTH,
        onChanged: (_) {},
        enablePinAutofill: true,
        enableActiveFill: true,
        textStyle: TextStyle(color: Palette.scorpion),
        pinTheme: PinTheme(
          shape: PinCodeFieldShape.circle,
          fieldHeight: SizePercentConfig.safeBlockHorizontal * 20,
          fieldWidth: SizePercentConfig.safeBlockHorizontal * 20,
          activeFillColor: Palette.concrete,
          inactiveFillColor: Palette.concrete,
          selectedFillColor: Palette.roseBud,
          activeColor: Palette.concrete,
          disabledColor: Palette.concrete,
          inactiveColor: Palette.concrete,
          selectedColor: Palette.roseBud,
        ),
        cursorColor: Palette.transparent,
        keyboardType: TextInputType.number,
      ),
    );
  }
}

【问题讨论】:

    标签: flutter flutter-layout flutter-animation


    【解决方案1】:

    为您的 ClipRect 小部件提供唯一键:

    如果“新”子节点与“旧”子节点的小部件类型和键相同,但参数不同,则 AnimatedSwitcher 不会在它们之间进行转换,因为就框架而言,它们是可以使用新参数更新相同的小部件和现有小部件。要强制进行转换,请在您希望被视为唯一的每个子小部件上设置一个 Key(通常是小部件数据上的一个 ValueKey,用于将该子小部件与其他小部件区分开来)。

    【讨论】:

    • 谢谢,但我已经有了键 _mobileKey_pinKey,当我调试它时,它会通过第一条语句,它只是没有动画。然后转到第二个语句,第二个小部件正确动画
    猜你喜欢
    • 2018-04-21
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 2018-11-11
    • 2018-08-24
    • 2021-01-12
    • 1970-01-01
    • 2021-05-07
    相关资源
    最近更新 更多