TOP(About this memo)) > 一覧(Flutter) > アニメーション
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() => runApp(const MaterialApp(home: MyTickerTest()));
class MyTickerTest extends StatefulWidget {
const MyTickerTest({super.key});
@override
State<MyTickerTest> createState() => _MyTickerTestState();
}
double? _x;
double? _y;
class _MyTickerTestState extends State<MyTickerTest>
with SingleTickerProviderStateMixin {
late Ticker _ticker;
@override
void initState() {
super.initState();
_ticker = createTicker((elapsed) {
final double elapsedInSeconds =
elapsed.inMicroseconds.toDouble() / Duration.microsecondsPerSecond;
if (elapsedInSeconds > 3) {
_ticker.stop();
}
if (_x != null) {
_x = _x! + 1.0;
_y = _y! + 1.0;
}
setState(() {});
});
_ticker.start();
}
@override
void dispose() {
super.dispose();
_ticker.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomPaint(
foregroundPainter: MyPainter(),
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
),
);
}
}
class MyPainter extends CustomPainter {
MyPainter();
@override
void paint(Canvas canvas, Size size) {
if (_x == null) {
_x = size.width / 2;
_y = size.height / 2;
}
canvas.drawCircle(Offset(_x!, _y!), 10.0, Paint()..color = Colors.blue);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
An animation with a value of type T.
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
void main() {
runApp(const MaterialApp(
home: Scaffold(
body: Center(child: AnimationControllerTest()),
)));
}
class AnimationControllerTest extends StatefulWidget {
const AnimationControllerTest({super.key});
@override
State<AnimationControllerTest> createState() =>
_AnimationControllerTestState();
}
enum BoundType { bound1, bound100, unbound }
class _AnimationControllerTestState extends State<AnimationControllerTest>
with TickerProviderStateMixin {
late AnimationController controller;
BoundType boundType = BoundType.bound1;
@override
void initState() {
super.initState();
create(true);
}
create([bool initial = false]) {
if (!initial) controller.dispose();
switch (boundType) {
case BoundType.bound1:
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 1000));
case BoundType.bound100:
controller = AnimationController(
upperBound: 100.0,
lowerBound: -100,
vsync: this,
duration: const Duration(milliseconds: 1000));
case BoundType.unbound:
controller = AnimationController.unbounded(
vsync: this, duration: const Duration(milliseconds: 1000));
}
controller.addListener(() {
debugPrint(controller.value.toString());
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("duration: ${controller.duration}"),
Text("value: ${controller.value.toString()}"),
Text("velocity: ${controller.velocity.toString()}"),
Text("status: ${controller.status.toString()}"),
Text("animationBehavior: ${controller.animationBehavior}"),
Text(
"lastElapsedDuration: ${controller.lastElapsedDuration.toString()}"),
Text(
"lowerBound: ${controller.lowerBound}, upperBound: ${controller.upperBound}"),
DropdownButton(
value: boundType,
items: BoundType.values
.map((e) => DropdownMenuItem(value: e, child: Text(e.name)))
.toList(),
onChanged: (value) {
boundType = value!;
create();
setState(() {});
}),
TextButton(
onPressed: () {
controller.forward();
},
child: const Text("foward")),
TextButton(
onPressed: () {
controller.stop();
},
child: const Text("stop")),
TextButton(
onPressed: () {
controller.reverse();
},
child: const Text("reverse")),
TextButton(
onPressed: () {
controller.reset();
},
child: const Text("reset")),
TextButton(
onPressed: boundType == BoundType.bound1
? () {
controller.repeat();
}
: null,
child: const Text("repeat")),
TextButton(
onPressed: () {
controller.fling();
},
child: const Text("fling")),
TextButton(
onPressed: () {
controller.animateTo(1.0, curve: Curves.bounceIn);
},
child: const Text("animateTo(bounceIn)")),
TextButton(
onPressed: () {
controller.animateWith(GravitySimulation(10.0, 0.0, 80.0, 0.0));
},
child: const Text("animateWith(GravitySimulation)")),
],
);
}
}
import 'dart:math';
import 'package:flutter/material.dart';
class TweenTest extends StatefulWidget {
const TweenTest({super.key});
@override
State<TweenTest> createState() => _TweenTestState();
}
class _TweenTestState extends State<TweenTest>
with SingleTickerProviderStateMixin {
final _scaleTween = Tween<double>(begin: 1.0, end: 0.01);
final _rotateTween = Tween<double>(begin: 0, end: 360);
final _duration = 3000;
late AnimationController _animationController;
late Animation _scaleAnimation;
late Animation _rotateAnimation;
late Animation _sequenseAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: Duration(milliseconds: _duration),
vsync: this,
);
_scaleAnimation = _scaleTween.animate(_animationController)
..addListener(() {
setState(() {});
});
_rotateAnimation = _rotateTween
.chain(CurveTween(curve: Curves.easeIn))
.animate(_animationController)
..addListener(() {
setState(() {});
});
_sequenseAnimation = TweenSequence<double>(
<TweenSequenceItem<double>>[
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0.0, end: 300.0)
.chain(CurveTween(curve: Curves.bounceOut)),
weight: 40.0,
),
TweenSequenceItem<double>(
tween: ConstantTween<double>(300.0),
weight: 40.0,
),
TweenSequenceItem<double>(
tween: Tween<double>(begin: 300.0, end: 0.0)
.chain(CurveTween(curve: Curves.easeOut)),
weight: 20.0,
),
],
).animate(_animationController);
_animationController.repeat();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Transform.translate(
offset: Offset(0.0, _sequenseAnimation.value),
child: const FlutterLogo(
size: 100.0,
),
),
Transform.translate(
offset: Offset(
0.0,
MediaQuery.of(context).size.width *
0.5 *
_animationController.value),
child: Transform.rotate(
angle: pi / 180 * _rotateAnimation.value,
child: Transform.scale(
scale: _scaleAnimation.value,
child: const SizedBox(
height: 100.0,
width: 100.0,
child: ColoredBox(
color: Colors.black,
),
),
),
),
)
],
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
abstract class Animatable<T> {
//...
T transform(double t);
T evaluate(Animation<double> animation) => transform(animation.value);
Animation<T> animate(Animation<double> parent) {
return _AnimatedEvaluation<T>(parent, this);
}
Animatable<T> chain(Animatable<double> parent) {
return _ChainedEvaluation<T>(parent, this);
}
}
//...
class _AnimatedEvaluation<T> extends Animation<T> with AnimationWithParentMixin<double> {
_AnimatedEvaluation(this.parent, this._evaluatable);
// ...
@override
T get value => _evaluatable.evaluate(parent);
// ...
}
class Tween<T extends Object?> extends Animatable<T> {
//...
@protected
T lerp(double t) {
return (begin as dynamic) + ((end as dynamic) - (begin as dynamic)) * t as T;
}
@override
T transform(double t) {
if (t == 0.0) {
return begin as T;
}
if (t == 1.0) {
return end as T;
}
return lerp(t);
}
//...
}
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
home: Scaffold(
body: Center(
child: TextFieldTest(),
),
)));
}
class TextFieldTest extends StatefulWidget {
const TextFieldTest({super.key});
@override
State<TextFieldTest> createState() => _TextFieldTestState();
}
class _TextFieldTestState extends State<TextFieldTest>
with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
final ticker = createTicker((_) {
setState(() {});
});
ticker.start();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(
controller: TextEditingController(),
),
),
);
}
}