フラッター:模造Flipboardの画像の3Dフリップアニメーションを実現するためにどのように教えました

リファレンスのアイデア: スローラインました

全体的な効果

いくつかの単語のリトル男、に直接的な影響

これは、3つに分割されているアニメーション処理を見て、見つけることができます

  • プロセス:下に傾け
  • プロセスII:上げます

工程III:右に傾けます

三次元画像は、二次元平面上に投影しました

X軸周りの画像、2つの回転平面に投影された画像の左側面図で、回転中右側の三次元図。

プロセス

画像は二つの部分に分けることができ、上半分が完全に動かなかった、X軸周りの回転の下半分は、回転角変更処理の効果を達成することができます

プロセス2

二もう少し複雑なプロセス、特定のフレームの場合を見て

レッドは、下半分に傾けて、上半分が傾くことはないので、2つの部分に分かれて垂直にプロット検討します

下半

  1. z軸は約20度の画像回転
  2. クロップ画像の半分だけを削除
  3. 画像は、X軸の周りに45度回転しました
  4. z軸の周り画像-20度

上半

  1. z軸は約20度の画像回転
  2. クロップ画像は、ちょうど上半分を取ります
  3. 0度のx軸回転周りピクチャ(なぜ?コーディング容易にするために、プロセスおよび他のプロセスを統一します)
  4. z軸の周り画像-20度

スプライス

2つの部分をステッチすると、2つのフレームの間有効です

2を達成するために、アニメーション処理

X軸周りの角度を保持し、各フレームを実現することができる2つのアニメーションプロセスにz軸周りの角度を変化させる、固定されています。

向上させる処理(符号化促進)

プロセスの約半分

  1. z軸に関する画像0度
  2. クロップ画像の半分だけを削除
  3. x軸周りの回転の角度で写真
  4. z軸に関する画像0度

x軸の回転角度を変更すると、プロセスは、アニメーションの下半分に達成することができることができます

プロセスの上半部

  1. z軸に関する画像0度
  2. クロップ画像は、ちょうど上半分を取ります
  3. X軸周りの写真0度回転
  4. z軸に関する画像0度

プロセス3

三つのプロセスと同様のプロセス、それらを繰り返しません。

アニメーション全体の特定のパラメータ

  • プロセス:

    • 上半分:回転角度が0であります
    • 下部半分:Z軸回りの回転角度は常に0、0度から-45への遷移X軸周りの回転角であります
  • プロセスII:

    • 上部:0から270度までのz軸遷移約角、x軸回りの回転角度を0度に固定されています
    • 下部半分:0から270度までのz軸遷移周りの回転の角度、x軸周りの回転の角度は45度に固定されています
  • プロセス3

    • 上部:Z軸回りの回転角度は常に270度、0〜45度からx軸遷移周りの回転角であります
    • 下半分は、Z軸周りの回転の角度が常に270度であり、x軸周りの回転角度は常に0度です

コーディング

まず、継続的なプロセスに列挙、ロゴアニメーションを定義します

enum FlipAnimationSteps { animation_step_1, animation_step_2, animation_step_3 }
复制代码

パラメータをアニメーション化、アニメーションの状態を監視

class _FlipAnimationApp extends State<FlipAnimationApp>
    with SingleTickerProviderStateMixin {
  var imageWidget = Image.asset(
    'images/mario.jpg',
    width: 300.0,
    height: 300.0,
  );

  AnimationController controller;

  CurvedAnimation animation;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 1), vsync: this);
    animation = CurvedAnimation(
      parent: controller,
      curve: Curves.easeInOut,
    )..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          switch (currentFlipAnimationStep) {
            case FlipAnimationSteps.animation_step_1:
              currentFlipAnimationStep = FlipAnimationSteps.animation_step_2;
              controller.reset();
              controller.forward();
              break;

            case FlipAnimationSteps.animation_step_2:
              currentFlipAnimationStep = FlipAnimationSteps.animation_step_3;
              controller.reset();
              controller.forward();
              break;
            case FlipAnimationSteps.animation_step_3:
              break;
          }
        }
      });

    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return AnimateFlipWidget(
      animation: animation,
      child: imageWidget,
    );
  }

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

复制代码

のは、コアクラスを見てみましょうAnimateFlipWidgetその中のメインロジックに関連し、アニメーション。

class AnimateFlipWidget extends AnimatedWidget {
  final Widget child;

  double _currentTopRotationXRadian = 0;
  double _currentBottomRotationXRadian = 0;
  double _currentRotationZRadian = 0;

  static final _topRotationXRadianTween =
      Tween<double>(begin: 0, end: math.pi / 4);
  static final _bottomRotationXRadianTween =
      Tween<double>(begin: 0, end: -math.pi / 4);
  static final _rotationZRadianTween =
      Tween<double>(begin: 0, end: (1 + 1 / 2) * math.pi);

  AnimateFlipWidget({Key key, Animation<double> animation, this.child})
      : super(key: key, listenable: animation);

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;

    return Center(
      child: Container(
        child: Stack(
          children: [
            Transform(
              alignment: Alignment.center,
              transform: Matrix4.rotationZ(currentFlipAnimationStep ==
                      FlipAnimationSteps.animation_step_2
                  ? _rotationZRadianTween.evaluate(animation) * -1
                  : _currentRotationZRadian * -1),
              child: Transform(
                transform: Matrix4.identity()
                  ..setEntry(3, 2, 0.002)
                  ..rotateX(currentFlipAnimationStep ==
                          FlipAnimationSteps.animation_step_3
                      ? _currentTopRotationXRadian =
                          _topRotationXRadianTween.evaluate(animation)
                      : _currentTopRotationXRadian),
                alignment: Alignment.center,
                child: ClipRect(
                  clipper: _TopClipper(context),
                  child: Transform(
                    alignment: Alignment.center,
                    transform: Matrix4.rotationZ(currentFlipAnimationStep ==
                            FlipAnimationSteps.animation_step_2
                        ? _currentRotationZRadian =
                            _rotationZRadianTween.evaluate(animation)
                        : _currentRotationZRadian),
                    child: child,
                  ),
                ),
              ),
            ),
            Transform(
              alignment: Alignment.center,
              transform: Matrix4.rotationZ(currentFlipAnimationStep ==
                      FlipAnimationSteps.animation_step_2
                  ? _rotationZRadianTween.evaluate(animation) * -1
                  : _currentRotationZRadian * -1),
              child: Transform(
                transform: Matrix4.identity()
                  ..setEntry(3, 2, 0.002)
                  ..rotateX(currentFlipAnimationStep ==
                          FlipAnimationSteps.animation_step_1
                      ? _currentBottomRotationXRadian =
                          _bottomRotationXRadianTween.evaluate(animation)
                      : _currentBottomRotationXRadian),
                alignment: Alignment.center,
                child: ClipRect(
                  clipper: _BottomClipper(context),
                  child: Transform(
                    alignment: Alignment.center,
                    transform: Matrix4.rotationZ(currentFlipAnimationStep ==
                            FlipAnimationSteps.animation_step_2
                        ? _currentRotationZRadian =
                            _rotationZRadianTween.evaluate(animation)
                        : _currentRotationZRadian),
                    child: child,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

复制代码

このクラスは返しStack(:できませんレイアウトを、変換結果は、上半分と重畳の下半分であることができるColumnオハイオ州レイアウト)、childrenそのうちの2つがTransform2つの部分は変更された後の結果を。二つに見出すことができTransform、それは、上記変換処理に沿ったものである(Z軸周り-軸Xについて>回転- - >トリミング> Z軸回りに戻します)。

仕立てのプロセスの下半分を見てください

class _BottomClipper extends CustomClipper<Rect> {
  final BuildContext context;

  _BottomClipper(this.context);

  @override
  Rect getClip(Size size) {
    return new Rect.fromLTRB(
        -size.width, size.height / 2, size.width * 2, size.height * 2);
  }

  @override
  bool shouldReclip(CustomClipper<Rect> oldClipper) {
    return true;
  }
}
复制代码

CustomClipperクラスを継承するクラスを定義し、getClipは、特定のトリミング範囲を指定して書き換えます。

ソース

ソースここでのポイントそれのようなああ星

ます。https://juejin.im/post/5d0b4e65e51d45105e0212d6で再現

おすすめ

転載: blog.csdn.net/weixin_34224941/article/details/93162714