[Fluth]状態が変化し続ける可変アニメーション
私は最近Flutterのアニメーションを理解して開発しています.アニメーションは非常に重要な要素であり、Fluter 2.0からWEBまでをサポートし、Reactなどの既存のWebフレームワークと競争力を維持していると思います.
Basic Animations in Flutter
Set Duration very long
Repeat() Method
addStatusListener
Flutterのアニメーションを使用したことがある人は、上記の3つの方法を使用すると、アニメーションは無限に実行されますが、アニメーションは常に同じアニメーションです.しかし、これは私が望んでいるものではありません.反射球のアニメーションを作成するには、パラメータを常に変化させなければなりません.例えば、ボールは移動しながら位置を変化させ続け、位置の変化に伴って壁面衝突を満たす条件下でも方向を変化させる.もちろん!測定可能な経路であるため、予め球の移動経路を設定してから直接()を繰り返すことができる.でも価値がない
このように構成されたアニメーションの変数が変化するアニメーションを可変アニメーションと呼ぶことにしました!
上記の3つ目の方法では、AnimationStatusとAnimationの関係は何ですか?AndroidスタジオでF 4を押してからアニメーションを行います.dartファイルを表示すると、次のコメントが表示されます.
次にif文でvalue値を0に設定すると、再び.forward()メソッドを実行できます!まずはここまでrepeat()と同じ機能を持ちます.
ここで重要なのは、setState文を使用してアニメーションの情報を変更し続けることです.
Conclusion
Basic Animations in Flutter
flutterが提供する基本アニメーションコンポーネントを使用して、簡単なアニメーションを実現することができます.例えばScale Transition、Fade Transitionなどの部品.さらに、より豊富なアニメーションを作成するために、Animated Builder、Tween Animation Builderなどのコンポーネントを使用することもできます.しかし、私は最近、これらの部品のアニメーションを通じていつも同じアニメーションしか表示されないことを開発し、体験しました.△これが正しい言い方かどうか分かりません.この文章を読むと、私の言うことがわかりますよ.だから私はFlutterでもっと特別なアニメーションを実現したいと思っています.
Reflecting Ball Animation
ReflectBall(
ballRad: 20,
mapXsize: 300,
mapYsize: 500,
xPosition: 100,
yPosition: 200,
xSpeed: 4,
ySpeed: 4,
);
これが実現したいアニメーション部品ReflectBallです.緑の箱の中にボールが動いていて、壁にぶつかると反射します.これがどのように実現されたのか説明します.
Factors
上のReflectBallの部品を見ると、入力値としていくつかのパラメータがあります.ボールの半径、ボールが移動する箱の大きさ、ボールの初期位置、ボールの速度です.これらのパラメータは必要だと思いますので、requiredオプションを追加しました.class ReflectBall extends StatefulWidget {
final double mapXsize;
final double mapYsize;
final double xPosition;
final double yPosition;
final int ballRad;
final double xVector;
final double yVector;
final double xSpeed;
final double ySpeed;
const ReflectBall({Key? key,
required this.mapXsize,
required this.mapYsize,
required this.xPosition,
required this.yPosition,
required this.ballRad,
this.xVector = 1,
this.yVector = 1,
required this.xSpeed,
required this.ySpeed
}) : super(key: key);
_ReflectBallState createState() => _ReflectBallState();
}
Infinite Animation
前述したように、この球の反射アニメーションは無限に続きます.Fluthでアニメーションを再生し続けるには、以下の簡単な方法があります.
ReflectBall(
ballRad: 20,
mapXsize: 300,
mapYsize: 500,
xPosition: 100,
yPosition: 200,
xSpeed: 4,
ySpeed: 4,
);
これが実現したいアニメーション部品ReflectBallです.緑の箱の中にボールが動いていて、壁にぶつかると反射します.これがどのように実現されたのか説明します.Factors
上のReflectBallの部品を見ると、入力値としていくつかのパラメータがあります.ボールの半径、ボールが移動する箱の大きさ、ボールの初期位置、ボールの速度です.これらのパラメータは必要だと思いますので、requiredオプションを追加しました.
class ReflectBall extends StatefulWidget {
final double mapXsize;
final double mapYsize;
final double xPosition;
final double yPosition;
final int ballRad;
final double xVector;
final double yVector;
final double xSpeed;
final double ySpeed;
const ReflectBall({Key? key,
required this.mapXsize,
required this.mapYsize,
required this.xPosition,
required this.yPosition,
required this.ballRad,
this.xVector = 1,
this.yVector = 1,
required this.xSpeed,
required this.ySpeed
}) : super(key: key);
_ReflectBallState createState() => _ReflectBallState();
}
Infinite Animation
前述したように、この球の反射アニメーションは無限に続きます.Fluthでアニメーションを再生し続けるには、以下の簡単な方法があります.
Set Duration very long
AnimationController(
vsync: this,
duration: Duration(seconds: 1000)
);
正確には、無限ではありませんが、一般的には1つの画面で何時間も見ることはありません.Repeat() Method
_animationController.repeat();
コードに従って繰り返す.addStatusListener
_animationController.forward();
_animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_animationController.reverse();
} else if (status == AnimationStatus.dismissed) {
_animationController.forward();
}
});
これは、Fluterアニメーションのアニメーション状態値を制御する方法です.AからBまでのアニメーションがある場合、上のコードはAからBで、BからAまでのアニメーションが繰り返されます.このように構成されたアニメーションの変数が変化するアニメーションを可変アニメーションと呼ぶことにしました!
Infinite Variable Animation
上記の3つ目の方法では、AnimationStatusとAnimationの関係は何ですか?AndroidスタジオでF 4を押してからアニメーションを行います.dartファイルを表示すると、次のコメントが表示されます.
// The result of this function includes an icon describing the status of this
// [Animation] object:
//
// * "▶": [AnimationStatus.forward] ([value] increasing)
// * "◀": [AnimationStatus.reverse] ([value] decreasing)
// * "⏭": [AnimationStatus.completed] ([value] == 1.0)
// * "⏮": [AnimationStatus.dismissed] ([value] == 0.0)
この注釈により、Animationの値がAnimationStatusを決定します!だから私は次のコードを書きました. _animationController.forward();
_animationController.addStatusListener((status) {
if(status == AnimationStatus.completed ){
_animationController.value=0;
_animationController.forward();
}
});
_animationController.value値は、アニメーションの進行に伴って0から1に連続して増加します.コードの最初の行.forward()メソッドでアニメーションを1回実行し、0の値を1に設定します.AnimationStatusは完了し、addStatusListerはifクエリー条件を確立します.次にif文でvalue値を0に設定すると、再び.forward()メソッドを実行できます!まずはここまでrepeat()と同じ機能を持ちます.
_animationController.forward();
_animationController.addStatusListener((status) {
if(status == AnimationStatus.completed ){
setState(() {
if(xPos >= (widget.mapXsize - widget.ballRad) || xPos <= widget.ballRad){
xVec*=-1;
}
if(yPos >= (widget.mapYsize - widget.ballRad) || yPos <= widget.ballRad){
yVec*=-1;
}
xPos+=widget.xSpeed*xVec;
yPos+=widget.ySpeed*yVec;
});
_animationController.value=0;
_animationController.forward();
}
});
でもsetState文を追加できるようになりました!!上のコードではsetStateゲート内のコードがボールの位置が所定のマップサイズからずれると、ボールのベクトル方向が反転し、x軸とy軸でボールの位置を速度X方向に加算します.(2 Dベクトル分解)ここで重要なのは、setState文を使用してアニメーションの情報を変更し続けることです.
Build Widgets
build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Container(
width: widget.mapXsize,
height: widget.mapYsize,
color: Colors.lightGreen,
child: CustomPaint(
painter: _ball(
animationValue: _animationController.value,
xVector: xVec,
yVector: yVec,
xPosition: xPos,
yPosition: yPos,
ballRad: widget.ballRad,
xSpeed: widget.xSpeed,
ySpeed: widget.ySpeed
),
),
);
},
);
}
Widget
class _ball extends CustomPainter {
final animationValue;
final xPosition;
final yPosition;
final xVector;
final yVector;
final ballRad;
final xSpeed;
final ySpeed;
_ball({
required this.animationValue,
required this.xPosition,
required this.yPosition,
required this.xVector,
required this.yVector,
required this.ballRad,
required this.xSpeed,
required this.ySpeed,
});
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.indigoAccent
..style = PaintingStyle.stroke
..strokeWidth = 2;
Path path = Path();
for(double i=0; i<ballRad; i++){
path.addOval(Rect.fromCircle(
center: Offset(
xPosition + animationValue*xSpeed*xVector,
yPosition + animationValue*ySpeed*yVector,
),
radius: i
));
}
path.close();
canvas.drawPath(path, paint);
}
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Animated BuilderとCustom Paintを使いました.Custom Paint Classで、pathのaddoval文とfor文で円を描きます.x軸位置、y軸位置などの値をパラメータに戻し直し、球を他の位置に描画し続けることができます.Conclusion
私が望むアニメーションを実現するために100%完璧なコードであることは保証できません.アニメーションの描画中の最適化などの面で改善が必要です.しかし、私はそれを実現すると同時に、自分の力でグーグルにも見つからない答えを探して、ある程度この問題を解決したことは、非常に大きな意味を持っています.本当に嬉しかった
もし私の文章を見たら、私のコードに問題があるか、改善する必要があるところがあれば、必ず!広告を貼ってほしいです.
Full Code import 'package:flutter/material.dart';
class ReflectBall extends StatefulWidget {
final double mapXsize;
final double mapYsize;
final double xPosition;
final double yPosition;
final int ballRad;
final double xVector;
final double yVector;
final double xSpeed;
final double ySpeed;
const ReflectBall({Key? key,
required this.mapXsize,
required this.mapYsize,
required this.xPosition,
required this.yPosition,
required this.ballRad,
this.xVector = 1,
this.yVector = 1,
required this.xSpeed,
required this.ySpeed
}) : super(key: key);
_ReflectBallState createState() => _ReflectBallState();
}
class _ReflectBallState extends State<ReflectBall> with SingleTickerProviderStateMixin{
late AnimationController _animationController;
late double xPos;
late double yPos;
late double xVec;
late double yVec;
void initState() {
// TODO: implement initState
super.initState();
xPos = widget.xPosition;
yPos = widget.yPosition;
xVec = widget.xVector;
yVec = widget.yVector;
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1)
);
_animationController.forward();
_animationController.addStatusListener((status) {
if(status == AnimationStatus.completed ){
setState(() {
if(xPos >= (widget.mapXsize - widget.ballRad) || xPos <= widget.ballRad){
xVec*=-1;
}
if(yPos >= (widget.mapYsize - widget.ballRad) || yPos <= widget.ballRad){
yVec*=-1;
}
xPos+=widget.xSpeed*xVec;
yPos+=widget.ySpeed*yVec;
});
_animationController.value=0;
_animationController.forward();
}
});
}
void dispose(){
_animationController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Container(
width: widget.mapXsize,
height: widget.mapYsize,
color: Colors.lightGreen,
child: CustomPaint(
painter: _ball(
animationValue: _animationController.value,
xVector: xVec,
yVector: yVec,
xPosition: xPos,
yPosition: yPos,
ballRad: widget.ballRad,
xSpeed: widget.xSpeed,
ySpeed: widget.ySpeed
),
),
);
},
);
}
}
class _ball extends CustomPainter {
final animationValue;
final xPosition;
final yPosition;
final xVector;
final yVector;
final ballRad;
final xSpeed;
final ySpeed;
_ball({
required this.animationValue,
required this.xPosition,
required this.yPosition,
required this.xVector,
required this.yVector,
required this.ballRad,
required this.xSpeed,
required this.ySpeed,
});
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.indigoAccent
..style = PaintingStyle.stroke
..strokeWidth = 2;
Path path = Path();
for(double i=0; i<ballRad; i++){
path.addOval(Rect.fromCircle(
center: Offset(
xPosition + animationValue*xSpeed*xVector,
yPosition + animationValue*ySpeed*yVector,
),
radius: i
));
}
path.close();
canvas.drawPath(path, paint);
}
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Reference
この問題について([Fluth]状態が変化し続ける可変アニメーション), 我々は、より多くの情報をここで見つけました
https://velog.io/@edge/Flutter-무한히-지속되며-상태가-계속-변하는-가변-Animation
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
import 'package:flutter/material.dart';
class ReflectBall extends StatefulWidget {
final double mapXsize;
final double mapYsize;
final double xPosition;
final double yPosition;
final int ballRad;
final double xVector;
final double yVector;
final double xSpeed;
final double ySpeed;
const ReflectBall({Key? key,
required this.mapXsize,
required this.mapYsize,
required this.xPosition,
required this.yPosition,
required this.ballRad,
this.xVector = 1,
this.yVector = 1,
required this.xSpeed,
required this.ySpeed
}) : super(key: key);
_ReflectBallState createState() => _ReflectBallState();
}
class _ReflectBallState extends State<ReflectBall> with SingleTickerProviderStateMixin{
late AnimationController _animationController;
late double xPos;
late double yPos;
late double xVec;
late double yVec;
void initState() {
// TODO: implement initState
super.initState();
xPos = widget.xPosition;
yPos = widget.yPosition;
xVec = widget.xVector;
yVec = widget.yVector;
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1)
);
_animationController.forward();
_animationController.addStatusListener((status) {
if(status == AnimationStatus.completed ){
setState(() {
if(xPos >= (widget.mapXsize - widget.ballRad) || xPos <= widget.ballRad){
xVec*=-1;
}
if(yPos >= (widget.mapYsize - widget.ballRad) || yPos <= widget.ballRad){
yVec*=-1;
}
xPos+=widget.xSpeed*xVec;
yPos+=widget.ySpeed*yVec;
});
_animationController.value=0;
_animationController.forward();
}
});
}
void dispose(){
_animationController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Container(
width: widget.mapXsize,
height: widget.mapYsize,
color: Colors.lightGreen,
child: CustomPaint(
painter: _ball(
animationValue: _animationController.value,
xVector: xVec,
yVector: yVec,
xPosition: xPos,
yPosition: yPos,
ballRad: widget.ballRad,
xSpeed: widget.xSpeed,
ySpeed: widget.ySpeed
),
),
);
},
);
}
}
class _ball extends CustomPainter {
final animationValue;
final xPosition;
final yPosition;
final xVector;
final yVector;
final ballRad;
final xSpeed;
final ySpeed;
_ball({
required this.animationValue,
required this.xPosition,
required this.yPosition,
required this.xVector,
required this.yVector,
required this.ballRad,
required this.xSpeed,
required this.ySpeed,
});
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..color = Colors.indigoAccent
..style = PaintingStyle.stroke
..strokeWidth = 2;
Path path = Path();
for(double i=0; i<ballRad; i++){
path.addOval(Rect.fromCircle(
center: Offset(
xPosition + animationValue*xSpeed*xVector,
yPosition + animationValue*ySpeed*yVector,
),
radius: i
));
}
path.close();
canvas.drawPath(path, paint);
}
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Reference
この問題について([Fluth]状態が変化し続ける可変アニメーション), 我々は、より多くの情報をここで見つけました https://velog.io/@edge/Flutter-무한히-지속되며-상태가-계속-변하는-가변-Animationテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol