如何多次使用带动画的小部件

How can I use a widget with animation several times

我创建了一个带有动画的自定义小部件并使用了几次,但是当我尝试使用 controller.forward();动画仅适用于最后一个小部件。但是我想让我点击的小部件动画化,请帮助我如何实现它? 这是我的小部件:

import 'package:flutter/material.dart';
import 'package:project/colors.dart';//for colors

class Favourite extends StatefulWidget {
  final IconData icon;
  final Function function;
  final Color color;
  final Color bgColor;
  final double width;
  final double height;
  final double iconSize;
  Favourite({
    this.icon,
    this.function,
    this.color = blue,
    this.bgColor = white,
    this.height = 45,
    this.width = 45,
    this.iconSize = 40,
  });

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

AnimationController controller;

class _FavouriteState extends State<Favourite>
    with SingleTickerProviderStateMixin {
  Animation<double> animation;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this, // the SingleTickerProviderStateMixin
      duration: Duration(
          milliseconds: 300), // how long should the animation take to finish
      value: 0.1,
      upperBound: 1,
      lowerBound: 0.5,
    );
    animation =
        CurvedAnimation(parent: controller, curve: Curves.easeInOutCirc);
    controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      }
    });
  }

  @override
  dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height,
      margin: EdgeInsets.symmetric(horizontal: 8, vertical: 10),
      decoration: BoxDecoration(
        color: widget.bgColor,
        boxShadow: [
          BoxShadow(
            color: Colors.black26,
            blurRadius: 10,
          ),
        ],
        borderRadius: BorderRadius.all(
          Radius.circular(15),
        ),
      ),
      child: Center(
        child: ScaleTransition(
          scale: animation,
          child: IconButton(
            onPressed: widget.function,
            icon: Icon(
              widget.icon,
              color: widget.color,
              size: widget.iconSize,
            ),
          ),
        ),
      ),
    );
  }
}

因此,我想为最喜欢的按钮创建一个比例不断变化的小动画。以下是我的使用方法:

class LaptopBlock extends StatefulWidget {
  @override
  _LaptopBlockState createState() => _LaptopBlockState();
}

class _LaptopBlockState extends State<LaptopBlock> with SingleTickerProviderStateMixin{
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 380,
      child: ListView.builder(
        padding: EdgeInsets.all(25),
        scrollDirection: Axis.horizontal,
        itemCount: laptops.length,
        itemBuilder: (BuildContext context, int index) { ...
     Favourite(
      icon: laptops[index].isLiked == true
      ? Icons.favorite
      : Icons.favorite_border,
      function: () {
       setState(() {
        controller.forward();
        laptops[index].isLiked = !laptops[index].isLiked;
       });
      },
    ), ...

因此,当我点击第一个收藏小部件时,图标发生变化,但动画应用于 ListView.builder 中的最后一个,而不是我点击的那个。

在网上找不到答案,只好在这里问了,提前谢谢你,抱歉我的英语不好

我认为这是因为您在状态之外制作了 AnimationController class。尝试将其移动到状态 class。这样,您将为 Widget 的每个实例拥有不同的 AnimationController。

class _FavouriteState extends State<Favourite>
    with SingleTickerProviderStateMixin {
  AnimationController controller;

而不是

AnimationController controller;

class _FavouriteState extends State<Favourite>
    with SingleTickerProviderStateMixin {

所以最后是代码:

import 'package:flutter/material.dart';
import 'package:visar/colors.dart';

class Favourite extends StatefulWidget {
  final IconData icon;
  final function;
  final Color color;
  final Color bgColor;
  final double width;
  final double height;
  final double iconSize;
  Favourite({
    this.icon,
    this.function,
    this.color = blue,
    this.bgColor = white,
    this.height = 45,
    this.width = 45,
    this.iconSize = 30,
  });

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

class _FavouriteState extends State<Favourite>
    with SingleTickerProviderStateMixin {
  AnimationController controller; //placed controller inside of the class
  Animation<double> animation;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this, // the SingleTickerProviderStateMixin
      duration: Duration(
          milliseconds: 300), // how long should the animation take to finish
      value: 0.6,
      upperBound: 1,
      lowerBound: 0.6,
    );
    animation =
        CurvedAnimation(parent: controller, curve: Curves.easeInOutCirc);
    controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      }
    });
  }

  @override
  dispose() {
    controller.dispose();
    super.dispose();
  }

  void control() {
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height,
      margin: EdgeInsets.symmetric(horizontal: 8, vertical: 10),
      decoration: BoxDecoration(
        color: widget.bgColor,
        boxShadow: [
          BoxShadow(
            color: Colors.black26,
            blurRadius: 10,
          ),
        ],
        borderRadius: BorderRadius.all(
          Radius.circular(15),
        ),
      ),
      child: Center(
        child: ScaleTransition(
          scale: animation,
          child: IconButton(
            onPressed: () {
              widget.function(); //this line to run custom functions on using the widget
              controller.forward(); //always runs the animation
            },
            icon: Icon(
              widget.icon,
              color: widget.color,
              size: widget.iconSize,
            ),
          ),
        ),
      ),
    );
  }
}