I'm starting out on Flutter and trying to make an animation which rotates while fading in and out continuously. So far rotation works, but I'm having difficulties with the fading effect. The widget will gradually become transparent but right after one rotation, it jumps back into opaque before turning transparent again. I'm trying to fix this but I can't seem to find out how. Using .forward()
and .reverse()
doesn't work, but it's possible I may have implemented the opaque animation incorrectly.
class AnimatedLoader extends AnimatedWidget {
static final _opacityTween = new Tween<double>(begin: 1.0, end: 0.3);
AnimatedLoader({
Key key,
this.alignment: FractionalOffset.center,
Animation<double> turns,
Animation<double> animation,
this.child,
}) : super(key: key, listenable: turns);
Animation<double> get turns => listenable;
final FractionalOffset alignment;
final Widget child;
@override
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
final double turnsValue = turns.value;
final Matrix4 transform = new Matrix4.rotationZ(turnsValue * math.PI * 2.0);
return new Transform(
alignment: alignment,
transform: transform,
child: new Opacity(
opacity: _opacityTween.evaluate(animation),
child: child,
)
);
}
}
class AppLoader extends StatefulWidget {
AppLoaderState createState() => new AppLoaderState();
}
class AppLoaderState extends State<AppLoader> with TickerProviderStateMixin {
AnimationController _controller;
AnimationController _controllerOp;
Animation<double> animation;
@override initState(){
super.initState();
_controller = new AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this,
)..repeat();
_controllerOp = new AnimationController(
duration: const Duration(milliseconds: 800),
vsync: this,
);
animation = new Tween(begin: 0.0, end: 300.0).animate(_controllerOp);
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controllerOp.reverse();
} else if (status == AnimationStatus.dismissed) {
_controllerOp.forward();
}
});
_controllerOp.forward();
}
@override
Widget build(BuildContext context) {
return new Center (
child: new AnimatedLoader(
turns: _controller,
alignment: FractionalOffset.center,
animation: _controllerOp,
child: new Container(
margin: new EdgeInsets.symmetric(vertical: 10.0),
height: 150.0,
width: 150.0,
child: new FlutterLogo(),
)
),
);
}
Sorry for the big chunk of code, I'm unsure which part I could've made a mistake in.
I think you're on the right track, but you should only use one AnimationController
per AnimatedWidget
. I fixed some bugs in your code.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
Widget build(BuildContext context) {
return new Scaffold(
body: new AppLoader(),
);
}
}
class PulsateCurve extends Curve {
@override
double transform(double t) {
if (t == 0 || t == 1)
return 0.3;
return math.sin(t * math.PI) * 0.35 + 0.65;
}
}
class AnimatedLoader extends AnimatedWidget {
static final _opacityTween = new CurveTween(curve: new PulsateCurve());
AnimatedLoader({
Key key,
this.alignment: FractionalOffset.center,
Animation<double> animation,
this.child,
}) : super(key: key, listenable: animation);
final FractionalOffset alignment;
final Widget child;
@override
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
final Matrix4 transform = new Matrix4.rotationZ(animation.value * math.PI * 2.0);
return new Transform(
alignment: alignment,
transform: transform,
child: new Opacity(
opacity: _opacityTween.evaluate(animation),
child: child,
)
);
}
}
class AppLoader extends StatefulWidget {
AppLoaderState createState() => new AppLoaderState();
}
class AppLoaderState extends State<AppLoader> with TickerProviderStateMixin {
AnimationController _controller;
@override initState() {
super.initState();
_controller = new AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this,
)..repeat();
}
@override
Widget build(BuildContext context) {
return new Center (
child: new AnimatedLoader(
animation: _controller,
alignment: FractionalOffset.center,
child: new Container(
margin: new EdgeInsets.symmetric(vertical: 10.0),
height: 150.0,
width: 150.0,
child: new FlutterLogo(),
)
),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With