同一小部件​​上的多种动画行为 - Flutter Getx Simple Animations

发布于 2025-01-12 04:11:58 字数 6235 浏览 0 评论 0原文

我正在尝试构建一个列表视图,其中包含具有不同动画行为的卡片,具体取决于悬停等用户交互。悬停的卡片需要放大,列表中的其余卡片需要缩小并使其不透明。 如:

预期流畅度

查看代码:

import 'package:flutter/material.dart';

import 'package:get/get.dart';
import 'package:simple_animations/multi_tween/multi_tween.dart';
import 'package:simple_animations/simple_animations.dart';
import 'package:simple_animations/stateless_animation/custom_animation.dart';

import '../controllers/work_controller.dart';

class WorkView extends GetView<WorkController> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          flex: 1,
          child: Container(color: Colors.blueGrey),
        ),
        Expanded(
            flex: 2,
            child: SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: List.generate(
                  10,
                  (index) {
                    return MouseRegion(
                        onExit: (event) => controller.hoverIndex.value = -1,
                        onEnter: ((event) {
                          print("Setting index: $index");
                          controller.hoverIndex.value = index;
                        }),
                        child: AnimatedWorkCard(
                          index: index,
                        ));
                  },
                ),
              ),
            ))
      ],
    );
  }
}

class AnimatedWorkCard extends StatefulWidget {
  final int index;

  const AnimatedWorkCard({
    Key? key,
    required this.index,
  }) : super(key: key);

  @override
  State<AnimatedWorkCard> createState() => _AnimatedWorkCardState();
}

enum CardAnimationProps {
  isNotHoveredOpacity,
  isHoveredImgScale,
  isNotHoveredTranslateX,
  isHoveredTextTranslateY,
  isHoveredTextOpacity,
}

class _AnimatedWorkCardState extends State<AnimatedWorkCard> {
  final WorkController controller = Get.find();

  var animationControl = CustomAnimationControl.play;

  @override
  Widget build(BuildContext context) {
    return Obx(() {
      var isHovered = controller.hoverIndex.value == widget.index;

      if (!isHovered) {
        return CustomAnimation<TimelineValue<CardAnimationProps>>(
          control: animationControl,
          tween: createNotHoveredTween(),
          builder: (context, child, value) {
            return Transform.translate(
              offset: Offset(
                  value.get(CardAnimationProps.isNotHoveredTranslateX), 0),
              child: child,
            );
          },
          child: Card(
            color: Colors.amber,
            child: Container(
              width: Get.width * 0.2,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Work ${widget.index}',
                    style: TextStyle(
                      fontSize: Get.width * 0.03,
                    ),
                  ),
                  ElevatedButton(
                    child: Text('Hovering: ${controller.hoverIndex.value}'),
                    onPressed: () {
                      Get.toNamed('/work/${widget.index}');
                    },
                  ),
                ],
              ),
            ),
          ),
        );
      } else {
        return CustomAnimation<TimelineValue<CardAnimationProps>>(
          control: animationControl,
          tween: createTween(controller.hoverIndex.value, widget.index),
          builder: (context, child, value) {
            return Transform.scale(
                scale: value.get(CardAnimationProps.isHoveredImgScale),
                child: child ?? Container());
          },
          child: Card(
            color: Colors.amber,
            child: Container(
              width: Get.width * 0.2,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Work ${widget.index}',
                    style: TextStyle(
                      fontSize: Get.width * 0.03,
                    ),
                  ),
                  ElevatedButton(
                    child: Text('Hovering: ${controller.hoverIndex.value}'),
                    onPressed: () {
                      Get.toNamed('/work/${widget.index}');
                    },
                  ),
                ],
              ),
            ),
          ),
        );
      }
    });
  }

  createTween(int hoverIndex, int index) {
    TimelineTween timelineTween = TimelineTween<CardAnimationProps>();
    var scene =
        timelineTween.addScene(begin: 0.seconds, end: 2000.milliseconds);

    scene.animate(
      CardAnimationProps.isHoveredImgScale,
      tween: Tween<double>(begin: 1, end: 1.3),
    );

    scene.animate(
      CardAnimationProps.isHoveredTextOpacity,
      tween: Tween<double>(begin: 0, end: 1),
    );
    scene.animate(
      CardAnimationProps.isHoveredTextTranslateY,
      tween: Tween<double>(begin: 20, end: 0),
    );

    return timelineTween;
  }

  createNotHoveredTween() {
    TimelineTween timelineTween = TimelineTween<CardAnimationProps>();
    var scene =
        timelineTween.addScene(begin: 0.seconds, end: 2000.milliseconds);

    scene.animate(
      CardAnimationProps.isNotHoveredOpacity,
      tween: Tween<double>(begin: 1, end: 0.2),
    );

    scene.animate(
      CardAnimationProps.isNotHoveredTranslateX,
      tween: Tween<double>(
        begin: 0,
        end: 20,
      ),
    );

    return timelineTween;
  }
}

控制器代码:

import 'package:get/get.dart';

class WorkController extends GetxController {
  RxInt hoverIndex = (-1).obs;

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

  @override
  void onClose() {}
}

但动画不流畅,只是跳跃来自各州。

知道如何使这变得更顺利或可以考虑实施任何其他方式吗?

动画演示

I am trying to build a list view with cards with different animation behaviors depending on user interactions like hovering. The hovered card needs to be scaled up and the remaining cards in the list need to be scaled down and made less opaque.
Like:

Expected smoothness

View code:

import 'package:flutter/material.dart';

import 'package:get/get.dart';
import 'package:simple_animations/multi_tween/multi_tween.dart';
import 'package:simple_animations/simple_animations.dart';
import 'package:simple_animations/stateless_animation/custom_animation.dart';

import '../controllers/work_controller.dart';

class WorkView extends GetView<WorkController> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          flex: 1,
          child: Container(color: Colors.blueGrey),
        ),
        Expanded(
            flex: 2,
            child: SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: List.generate(
                  10,
                  (index) {
                    return MouseRegion(
                        onExit: (event) => controller.hoverIndex.value = -1,
                        onEnter: ((event) {
                          print("Setting index: $index");
                          controller.hoverIndex.value = index;
                        }),
                        child: AnimatedWorkCard(
                          index: index,
                        ));
                  },
                ),
              ),
            ))
      ],
    );
  }
}

class AnimatedWorkCard extends StatefulWidget {
  final int index;

  const AnimatedWorkCard({
    Key? key,
    required this.index,
  }) : super(key: key);

  @override
  State<AnimatedWorkCard> createState() => _AnimatedWorkCardState();
}

enum CardAnimationProps {
  isNotHoveredOpacity,
  isHoveredImgScale,
  isNotHoveredTranslateX,
  isHoveredTextTranslateY,
  isHoveredTextOpacity,
}

class _AnimatedWorkCardState extends State<AnimatedWorkCard> {
  final WorkController controller = Get.find();

  var animationControl = CustomAnimationControl.play;

  @override
  Widget build(BuildContext context) {
    return Obx(() {
      var isHovered = controller.hoverIndex.value == widget.index;

      if (!isHovered) {
        return CustomAnimation<TimelineValue<CardAnimationProps>>(
          control: animationControl,
          tween: createNotHoveredTween(),
          builder: (context, child, value) {
            return Transform.translate(
              offset: Offset(
                  value.get(CardAnimationProps.isNotHoveredTranslateX), 0),
              child: child,
            );
          },
          child: Card(
            color: Colors.amber,
            child: Container(
              width: Get.width * 0.2,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Work ${widget.index}',
                    style: TextStyle(
                      fontSize: Get.width * 0.03,
                    ),
                  ),
                  ElevatedButton(
                    child: Text('Hovering: ${controller.hoverIndex.value}'),
                    onPressed: () {
                      Get.toNamed('/work/${widget.index}');
                    },
                  ),
                ],
              ),
            ),
          ),
        );
      } else {
        return CustomAnimation<TimelineValue<CardAnimationProps>>(
          control: animationControl,
          tween: createTween(controller.hoverIndex.value, widget.index),
          builder: (context, child, value) {
            return Transform.scale(
                scale: value.get(CardAnimationProps.isHoveredImgScale),
                child: child ?? Container());
          },
          child: Card(
            color: Colors.amber,
            child: Container(
              width: Get.width * 0.2,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Work ${widget.index}',
                    style: TextStyle(
                      fontSize: Get.width * 0.03,
                    ),
                  ),
                  ElevatedButton(
                    child: Text('Hovering: ${controller.hoverIndex.value}'),
                    onPressed: () {
                      Get.toNamed('/work/${widget.index}');
                    },
                  ),
                ],
              ),
            ),
          ),
        );
      }
    });
  }

  createTween(int hoverIndex, int index) {
    TimelineTween timelineTween = TimelineTween<CardAnimationProps>();
    var scene =
        timelineTween.addScene(begin: 0.seconds, end: 2000.milliseconds);

    scene.animate(
      CardAnimationProps.isHoveredImgScale,
      tween: Tween<double>(begin: 1, end: 1.3),
    );

    scene.animate(
      CardAnimationProps.isHoveredTextOpacity,
      tween: Tween<double>(begin: 0, end: 1),
    );
    scene.animate(
      CardAnimationProps.isHoveredTextTranslateY,
      tween: Tween<double>(begin: 20, end: 0),
    );

    return timelineTween;
  }

  createNotHoveredTween() {
    TimelineTween timelineTween = TimelineTween<CardAnimationProps>();
    var scene =
        timelineTween.addScene(begin: 0.seconds, end: 2000.milliseconds);

    scene.animate(
      CardAnimationProps.isNotHoveredOpacity,
      tween: Tween<double>(begin: 1, end: 0.2),
    );

    scene.animate(
      CardAnimationProps.isNotHoveredTranslateX,
      tween: Tween<double>(
        begin: 0,
        end: 20,
      ),
    );

    return timelineTween;
  }
}

Controller code:

import 'package:get/get.dart';

class WorkController extends GetxController {
  RxInt hoverIndex = (-1).obs;

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

  @override
  void onClose() {}
}

But the animation is not smooth and it's just jumping from the states.

Any idea how this can made smoother or any other way this can be thought of implementing?

Animation demo

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文