リファレンスのアイデア: スローラインました
全体的な効果
いくつかの単語のリトル男、に直接的な影響
これは、3つに分割されているアニメーション処理を見て、見つけることができます
- プロセス:下に傾け
- プロセスII:上げます
工程III:右に傾けます
三次元画像は、二次元平面上に投影しました
X軸周りの画像、2つの回転平面に投影された画像の左側面図で、回転中右側の三次元図。
プロセス
画像は二つの部分に分けることができ、上半分が完全に動かなかった、X軸周りの回転の下半分は、回転角変更処理の効果を達成することができます
プロセス2
二もう少し複雑なプロセス、特定のフレームの場合を見て
レッドは、下半分に傾けて、上半分が傾くことはないので、2つの部分に分かれて垂直にプロット検討します
下半
- z軸は約20度の画像回転
- クロップ画像の半分だけを削除
- 画像は、X軸の周りに45度回転しました
- z軸の周り画像-20度
上半
- z軸は約20度の画像回転
- クロップ画像は、ちょうど上半分を取ります
- 0度のx軸回転周りピクチャ(なぜ?コーディング容易にするために、プロセスおよび他のプロセスを統一します)
- z軸の周り画像-20度
スプライス
2つの部分をステッチすると、2つのフレームの間有効です
2を達成するために、アニメーション処理
X軸周りの角度を保持し、各フレームを実現することができる2つのアニメーションプロセスにz軸周りの角度を変化させる、固定されています。
向上させる処理(符号化促進)
プロセスの約半分
- z軸に関する画像0度
- クロップ画像の半分だけを削除
- x軸周りの回転の角度で写真
- z軸に関する画像0度
x軸の回転角度を変更すると、プロセスは、アニメーションの下半分に達成することができることができます
プロセスの上半部
- z軸に関する画像0度
- クロップ画像は、ちょうど上半分を取ります
- X軸周りの写真0度回転
- 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つがTransform
2つの部分は変更された後の結果を。二つに見出すことができ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で再現