颤振-翻转动画-根据水龙头的位置翻转卡片的右侧或左侧

时间:2019-03-02 13:13:45

标签: flutter flutter-animation

我开始与Flutter一起玩,现在开始思考如何实现卡片翻转动画的最佳方法。

我找到了这个flip_card包裹,并且正在尝试根据自己的需要调整its source code

这是我现在拥有的应用程序:

import 'dart:math';
import 'package:flutter/material.dart';

void main() => runApp(FlipAnimationApp());

class FlipAnimationApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Flip animation"),
        ),
        body: Center(
          child: Container(
            width: 200,
            height: 200,
            child: WidgetFlipper(
              frontWidget: Container(
                color: Colors.green[200],
                child: Center(
                  child: Text(
                    "FRONT side.",
                  ),
                ),
              ),
              backWidget: Container(
                color: Colors.yellow[200],
                child: Center(
                  child: Text(
                    "BACK side.",
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class WidgetFlipper extends StatefulWidget {
  WidgetFlipper({
    Key key,
    this.frontWidget,
    this.backWidget,
  }) : super(key: key);

  final Widget frontWidget;
  final Widget backWidget;

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

class _WidgetFlipperState extends State<WidgetFlipper> with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation<double> _frontRotation;
  Animation<double> _backRotation;
  bool isFrontVisible = true;

  @override
  void initState() {
    super.initState();

    controller = AnimationController(duration: Duration(milliseconds: 500), vsync: this);
    _frontRotation = TweenSequence(
      <TweenSequenceItem<double>>[
        TweenSequenceItem<double>(
          tween: Tween(begin: 0.0, end: pi / 2).chain(CurveTween(curve: Curves.linear)),
          weight: 50.0,
        ),
        TweenSequenceItem<double>(
          tween: ConstantTween<double>(pi / 2),
          weight: 50.0,
        ),
      ],
    ).animate(controller);
    _backRotation = TweenSequence(
      <TweenSequenceItem<double>>[
        TweenSequenceItem<double>(
          tween: ConstantTween<double>(pi / 2),
          weight: 50.0,
        ),
        TweenSequenceItem<double>(
          tween: Tween(begin: -pi / 2, end: 0.0).chain(CurveTween(curve: Curves.linear)),
          weight: 50.0,
        ),
      ],
    ).animate(controller);
  }

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

  @override
  Widget build(BuildContext context) {
    return Stack(
      fit: StackFit.expand,
      children: [
        AnimatedCard(
          animation: _backRotation,
          child: widget.backWidget,
        ),
        AnimatedCard(
          animation: _frontRotation,
          child: widget.frontWidget,
        ),
        _tapDetectionControls(),
      ],
    );
  }

  Widget _tapDetectionControls() {
    return Stack(
      fit: StackFit.expand,
      children: <Widget>[
        GestureDetector(
          onTap: _leftRotation,
          child: FractionallySizedBox(
            widthFactor: 0.5,
            heightFactor: 1.0,
            alignment: Alignment.topLeft,
            child: Container(
              color: Colors.transparent,
            ),
          ),
        ),
        GestureDetector(
          onTap: _rightRotation,
          child: FractionallySizedBox(
            widthFactor: 0.5,
            heightFactor: 1.0,
            alignment: Alignment.topRight,
            child: Container(
              color: Colors.transparent,
            ),
          ),
        ),
      ],
    );
  }

  void _leftRotation() {
    _toggleSide();
  }

  void _rightRotation() {
    _toggleSide();
  }

  void _toggleSide() {
    if (isFrontVisible) {
      controller.forward();
      isFrontVisible = false;
    } else {
      controller.reverse();
      isFrontVisible = true;
    }
  }
}

class AnimatedCard extends StatelessWidget {
  AnimatedCard({
    this.child,
    this.animation,
  });

  final Widget child;
  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: animation,
      builder: (BuildContext context, Widget child) {
        var transform = Matrix4.identity();
        transform.setEntry(3, 2, 0.001);
        transform.rotateY(animation.value);
        return Transform(
          transform: transform,
          alignment: Alignment.center,
          child: child,
        );
      },
      child: child,
    );
  }
}

这是它的样子:

您如何建议根据轻击手势的位置(卡的右半部或左半部)调整代码以使卡在其右侧或左侧翻转?

2 个答案:

答案 0 :(得分:0)

尝试使用此代码,我对您的代码进行了一些更改,现在GestureDetector在小部件上的宽度相等,因此,当您点击框左侧时,它将反转动画,如果您点击在右侧,它将转发动画。

 Widget _tapDetectionControls() {
    return Flex(
      direction: Axis.horizontal,
      children: <Widget>[
        Expanded(
          flex: 1,
          child: GestureDetector(
            onTap: _leftRotation,
          ),
        ),
        Expanded(
          flex: 1,
          child: GestureDetector(
            onTap: _rightRotation,
          ),
        ),
      ],
    );
  }

  void _leftRotation() {
    controller.reverse();
  }

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

答案 1 :(得分:0)

您应该知道何时单击右侧或左侧来动态更改动画,因为可以使用标记isRightTap。然后,如果Tweens的值必须旋转到一侧或另一侧,则应将其取反。

您应该旋转的一侧是:

  • 如果正面可见并且您点击了左侧,则向左旋转;或者,因为背面动画是相反的,如果背面可见并且您点击了右侧,则向左旋转
  • 否则,向右旋转

这是我在问题中的代码中在_WidgetFlipperState中所做的更改:

_updateRotations(bool isRightTap) {
  setState(() {
    bool rotateToLeft = (isFrontVisible && !isRightTap) || !isFrontVisible && isRightTap;
    _frontRotation = TweenSequence(
      <TweenSequenceItem<double>>[
        TweenSequenceItem<double>(
          tween: Tween(begin: 0.0, end: rotateToLeft ? (pi / 2) : (-pi / 2))
              .chain(CurveTween(curve: Curves.linear)),
          weight: 50.0,
        ),
        TweenSequenceItem<double>(
          tween: ConstantTween<double>(rotateToLeft ? (-pi / 2) : (pi / 2)),
          weight: 50.0,
        ),
      ],
    ).animate(controller);
    _backRotation = TweenSequence(
      <TweenSequenceItem<double>>[
        TweenSequenceItem<double>(
          tween: ConstantTween<double>(rotateToLeft ? (pi / 2) : (-pi / 2)),
          weight: 50.0,
        ),
        TweenSequenceItem<double>(
          tween: Tween(begin: rotateToLeft ? (-pi / 2) : (pi / 2), end: 0.0)
              .chain(CurveTween(curve: Curves.linear)),
          weight: 50.0,
        ),
      ],
    ).animate(controller);
  });
}

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

void _leftRotation() {
  _toggleSide(false);
}

void _rightRotation() {
  _toggleSide(true);
}

void _toggleSide(bool isRightTap) {
  _updateRotations(isRightTap);
  if (isFrontVisible) {
    controller.forward();
    isFrontVisible = false;
  } else {
    controller.reverse();
    isFrontVisible = true;
  }
}