尽管有自己的动画控制器,但 Flutter 小部件共享

Flutter widgets sharing despite having their own animation controller

我有一个水平的小部件列表,当用户在小部件上拖动时,这些小部件能够在 X 轴上翻转。 (中间的大硬币)

使用左右箭头,用户可以循环浏览他们拥有的硬币。

但是,如果用户要抛一枚硬币,然后单击以循环到另一枚硬币,即使它是一个完全不同的对象,硬币也会保持抛掷状态。

硬币:

class Coin extends StatefulWidget {
  final Image frontImage = const Image(image: AssetImage("assets/logo.png"));
  final Image back = const Image(image: AssetImage("assets/logoback.png"));

  const Coin({Key? key}) : super(key: key);

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

class _CoinState extends State<Coin>
    with SingleTickerProviderStateMixin {
  late AnimationController controller;
  late Animation<double> animation;
  bool isFront = true;
  double dragPosition = 0;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
        duration: const Duration(milliseconds: 500), vsync: this);

    controller.addListener(() {
      setState(() {
        dragPosition = animation.value;
        setImageSide();
      });
    });
  }

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

  @override
  Widget build(BuildContext context) {
    Stack front = Stack(
      alignment: const Alignment(0, 0),
      children: [
        widget.frontImage,
        const Text("1", style: TextStyle(fontSize: 100, color: Colors.white))
      ],
    );

    final angle = dragPosition / 180 * math.pi;
    final transform = Matrix4.identity()
      ..setEntry(3, 2, 0.001)
      ..rotateY(angle);

    return GestureDetector(
      onHorizontalDragUpdate: (details) => setState(() {
        dragPosition -= details.delta.dx;
        dragPosition %= 360;
        setImageSide();
      }),
      onHorizontalDragEnd: (details) {
        double end = isFront ? (dragPosition > 180 ? 360 : 0) : 180;
        animation = Tween<double>(
          begin: dragPosition,
          end: end,
        ).animate(controller);
        controller.forward(from: 0);
      },
      child: Transform(
          transform: transform,
          alignment: Alignment.center,
          child: isFront
              ? front
              : Transform(
                  transform: Matrix4.identity()..rotateY(math.pi),
                  alignment: Alignment.center,
                  child: widget.back)),
    );
  }

  void setImageSide() {
    if (dragPosition <= 90 || dragPosition >= 270) {
      isFront = true;
    } else {
      isFront = false;
    }
  }
}

首页:

class _HomePageState extends State<HomePage> {

  int _currentIndex = 1;
  final List _coins = const [widgets.Coin(), widgets.Coin(), widgets.Coin()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // Main homepage contents
      body: Center(
          child: Column(
              // Column Alignment
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.max,

              // Main body of home page
              children: [
                Text(_currentIndex.toString()),

                const Spacer(), // Spacing

                // Centered Flip Coin widget
                Padding(
                  padding: const EdgeInsets.only(top: 40, bottom: 40),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [

                      // Back coin button
                      IconButton(
                        icon: Icon(Icons.arrow_back_ios, color: Colors.grey[600]),
                        onPressed: () {
                          if (_currentIndex != 0) {
                            setState(() {
                              _currentIndex--;
                            });
                          }}),

                      _coins[_currentIndex],   // Coin widget

                      // Forward coin button
                      IconButton(
                        icon: Icon(Icons.arrow_forward_ios, color: Colors.grey[600]),
                        onPressed: () {
                          if (_currentIndex < (_coins.length - 1)) {
                            setState(() {
                              _currentIndex++;
                            });
                          }})
                    ])),

                const Spacer(), // Spacing

                // Pushup button widget
                const Padding(
                    padding: EdgeInsets.only(left: 8, right: 8),
                    child: widgets.PushupButton()),

                // Group information widget
                const Padding(
                  padding: EdgeInsets.all(8.0),
                  child: widgets.GroupInfo(),
                ),
              ])),
        );
  }
}

Github(可能有点旧,主要是文件名不同) https://github.com/bens-schreiber/pushupapp

我已经通过打印当前索引和对象来确保左右按钮确实在对象之间循环,所以我可以确认它在循环。

如果有人知道为什么会这样,请告诉我。

不确定他们是如何共享 isFront 变量的,但是当我将 isFrontCoinState class 移动到 Coin class 然后它正确地保存了硬币的方向。