如何在无效输入时晃动 Flutter 中的小部件?

Pan*_*dhu 5 animation widget flutter

在我的注册表单上,我有一个复选框,每当用户在接受条款和条件之前尝试登录时,该复选框都需要摇晃一下。我怎样才能实现像 Flutter 这样的东西?

小智 7

import 'package:flutter/material.dart';

@immutable
class ShakeWidget extends StatelessWidget {
  final Duration duration;
  final double deltaX;
  final Widget child;
  final Curve curve;

  const ShakeWidget({
    Key key,
    this.duration = const Duration(milliseconds: 500),
    this.deltaX = 20,
    this.curve = Curves.bounceOut,
    this.child,
  }) : super(key: key);

  /// convert 0-1 to 0-1-0
  double shake(double animation) =>
      2 * (0.5 - (0.5 - curve.transform(animation)).abs());

  @override
  Widget build(BuildContext context) {
    return TweenAnimationBuilder<double>(
      key: key,
      tween: Tween(begin: 0.0, end: 1.0),
      duration: duration,
      builder: (context, animation, child) => Transform.translate(
        offset: Offset(deltaX * shake(animation), 0),
        child: child,
      ),
      child: child,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您需要重新启用抖动,只需将 ShakeWidget 键更改为某个随机键即可。


Era*_*ore 5

我以不同的方式实现了这一点,因为我希望能够控制持续时间并获得更剧烈的摇晃。我还希望能够轻松地将其添加为其他子小部件的包装器,因此我查找了如何使用键在子小部件中具有父控件操作。这是课程:

class ShakerState extends State<Shaker>   with SingleTickerProviderStateMixin {
  late AnimationController animationController;
  late Animation<double> animation;

  @override
  void initState() {
    super.initState();
    animationController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 800), // how long the shake happens
    )..addListener(() => setState(() {}));

    animation = Tween<double>(
      begin: 00.0,
      end: 120.0,
    ).animate(animationController);
  }

  math.Vector3 _shake() {
    double progress = animationController.value;
    double offset = sin(progress * pi * 10.0);  // change 10 to make it vibrate faster
    return math.Vector3(offset * 25, 0.0, 0.0);  // change 25 to make it vibrate wider
  }

  shake() {
    animationController.forward(from:0);
  }

  @override
  Widget build(BuildContext context) {
    return Transform(
        transform: Matrix4.translation(_shake()),
        child: widget.child,
      );
  }
}
Run Code Online (Sandbox Code Playgroud)

然后要使用它,您需要父母的钥匙:

  final GlobalKey<ShakerState> _shakeKey = GlobalKey<ShakerState>();
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的父体内做类似的事情(看看在我想要摇动的孩子周围使用“Shaker”的地方):

    ...
    Container(
      height: 50,
      width: 250,
      decoration: BoxDecoration(color: Colors.blue, borderRadius: BorderRadius.circular(20)),
      child: TextButton(
        onPressed: () => _handleEmailSignIn(loginController.text, loginPasswordController.text),
        child: Shaker(_shakeKey, Text('Login',   // <<================
          style: TextStyle(color: Colors.white, fontSize: 25),
        )),
      ),
    ),
    ...
Run Code Online (Sandbox Code Playgroud)

然后使用控制器,您可以在您想要的时候以编程方式触发摇动,如下所示(请参阅“_shakeKey”的使用):

  Future<void> _handleEmailSignIn(String user, password) async {
    try {
      await auth.signInWithEmailAndPassword(email: user, password: password);
      FocusScope.of(context).unfocus();
      await Navigator.pushNamedAndRemoveUntil(context, '/next_page',  ModalRoute.withName('/'));
    } on FirebaseAuthException catch (e) {

      _shakeKey.currentState?.shake(); // <<=============

      if (e.code == 'user-not-found') {
        print('No user found for that email.');
      } else if (e.code == 'wrong-password') {
        print('Wrong password provided for that user.');
      }
    }
    setState(() {});
  }
Run Code Online (Sandbox Code Playgroud)