RotationY Matrix4 not rotating fully - flutter

I have a text widget I want to rotate for 360 degrees only on Y axis.
Here is the code I currently have, it only rotates up to a certain point.
import 'package:flutter/material.dart';
class Loader extends StatefulWidget {
#override
_LoaderState createState() => _LoaderState();
}
class _LoaderState extends State<Loader> with SingleTickerProviderStateMixin {
Animation _rotate;
AnimationController _controller;
#override
void initState() {
super.initState();
_controller = new AnimationController(
vsync: this,
duration: new Duration(seconds: 1),
);
_rotate = Tween(begin: 0.0, end: 3.14 * 2).animate(_controller);
_controller.forward();
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
child: AnimatedBuilder(
animation: _controller,
child: Text("Flutter"),
builder: (BuildContext context, Widget _widget) {
return Transform(
transform: Matrix4.rotationY(_controller.value),
child: _widget,
);
},
),
);
}
}
Do you guys have any idea how to fix this?
Thanks!

add this
_rotate = Tween(begin: 0.0, end: 3.14 * 2).animate(_controller)
..addListener(() {
setState(() {});
});

Related

Cannot pinch zoom an image in flutter

I'm trying to pinch zoom an image that I have created in a separate widget, this widget is being called inside a dialog. Image gets loaded but not being pinched in and out.
here is my widget code:
class ImageWidget extends StatefulWidget {
const ImageWidget({Key? key}) : super(key: key);
#override
State<ImageWidget> createState() => _ImageWidgetState();
}
class _ImageWidgetState extends State<ImageWidget>
with SingleTickerProviderStateMixin {
final double minScale = 1;
final double maxScale = 4;
late TransformationController _transformationController;
late AnimationController _animationController;
Animation<Matrix4>? animation;
#override
void initState() {
// TODO: implement initState
super.initState();
_transformationController = TransformationController();
_animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 300))
..addListener(() {
_transformationController.value = animation!.value;
});
}
#override
void dispose() {
_transformationController.dispose();
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return InteractiveViewer(
transformationController: _transformationController,
clipBehavior: Clip.none,
minScale: minScale,
maxScale: maxScale,
onInteractionEnd: (details) {
resetAnimation();
},
panEnabled: false,
scaleEnabled: false,
child: AspectRatio(
aspectRatio: 2,
child: Image.asset(
'assets/capture.jpg',
),
));
}
void resetAnimation() {
animation = Matrix4Tween(
begin: _transformationController.value, end: Matrix4.identity())
.animate(
CurvedAnimation(parent: _animationController, curve: Curves.ease));
_animationController.forward(from: 0);
}
}
and here is how I called it inside the dialog:
onTap: () async {
await showDialog(
context: context, builder: (_) => const ImageWidget());
},
I'd be glad if anyone can help me out with it, thanks in advance!

Animation, increase and decrease the size

I have a problem with the animation, I want the heart to start small, increase and then decrease in size, as shown in the gif below.
Desired animation
But the current behavior is that the heart starts out big and then slows down.
Would anyone know what it would take to fix the animation?
Here is the flutter code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage();
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
Animation<double> _heartAnimation;
AnimationController _heartController;
#override
void dispose() {
_heartController.dispose();
super.dispose();
}
void _animate() {
_heartController
..reset()
..forward(from: 0.0)
..reverse(from: 1.0);
}
#override
void initState() {
super.initState();
final quick = const Duration(milliseconds: 500);
final scaleTween = Tween(begin: 0.0, end: 1.0);
_heartController = AnimationController(duration: quick, vsync: this);
_heartAnimation = scaleTween.animate(
CurvedAnimation(
parent: _heartController,
curve: Curves.elasticOut,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ScaleTransition(
scale: _heartAnimation,
child: Icon(Icons.favorite, size: 160.0, color: Colors.red),
)
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_animate();
},
child: Icon(Icons.favorite_rounded),
),
);
}
}
Try this code, it works for me perfectly. If you have any questions please let know.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: MyHomePage());
}
}
class MyHomePage extends StatefulWidget {
MyHomePage();
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController controller;
#override
void initState() {
super.initState();
final quick = const Duration(milliseconds: 500);
final scaleTween = Tween(begin: 0.0, end: 1.0);
controller = AnimationController(duration: quick, vsync: this);
animation = scaleTween.animate(
CurvedAnimation(
parent: controller,
curve: Curves.fastLinearToSlowEaseIn,
),
)..addListener(() {
setState(() => scale = animation.value);
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
void _animate() {
animation
..addStatusListener((AnimationStatus status) {
if (scale == 1.0) {
controller.reverse();
}
});
controller.forward();
}
double scale = 0.0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Transform.scale(
scale: scale,
child: Icon(
Icons.favorite,
size: 160.0,
color: Colors.red
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_animate();
},
child: Icon(Icons.favorite_rounded),
)
);
}
}

AnimatedBuilder with two different types of animations not working

I'm trying to animate the color and the value of a CircularProgressIndicator I want it to go from 0-1 and from pink to orange in 15 seconds. Here's everything I tried:
TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0, end: 1),
curve: Curves.easeOut,
duration: Duration(seconds: 15),
builder: (context, value, _) {
Color strokeColor = Colors.pink;
if (value > 0.5) strokeColor = Colors.orange;
return CircularProgressIndicator(
strokeWidth: 8, value: value, valueColor: AlwaysStoppedAnimation<Color>(strokeColor));
}),
That animated the value, but not the valueColor/stroke color. I have to somehow pass ColorTween(begin: Colors.pink, end: Colors.orange) to the valueColor, but I'm not sure how... I replacing the TweenAnimationBuilder with a AnimatedBuilder, but I ran into issues since the animation can only use 1 type of value, i.e. either a double or a color, but can't do both...
It's possible to use a AnimatedBuilder to pass a ColorTween and a Tween to control the color and the value of the CircularProgressIndicator, respectively.
In order to do so:
We need to use the SingleTickerProviderStateMixin on our parent StatefulWidget:
class _MyProgressIndicator extends State<MyProgressIndicator>
with SingleTickerProviderStateMixin {
// ...
}
Initialize the AnimationController, ColorTween, Tween<double>, and starting the AnimationController by overriding the initState() method:
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 15),
vsync: this,
);
_animationColor = ColorTween(
begin: Colors.pink,
end: Colors.orange,
).animate(_controller);
_animationValue = Tween<double>(begin: 0, end: 1).animate(_controller);
_controller.forward();
}
Don't forget the AnimationController by overriding the dispose() method!
#override
void dispose() {
_controller.dispose();
super.dispose();
}
A full example is displayed below:
import 'package:flutter/material.dart';
class MyProgressIndicator extends StatefulWidget {
MyProgressIndicator({Key key}) : super(key: key);
#override
_MyProgressIndicator createState() => _MyProgressIndicator();
}
class _MyProgressIndicator extends State<MyProgressIndicator>
with SingleTickerProviderStateMixin {
Animation<Color> _animationColor;
Animation<double> _animationValue;
AnimationController _controller;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 15),
vsync: this,
);
_animationColor = ColorTween(
begin: Colors.pink,
end: Colors.orange,
).animate(_controller);
_animationValue = Tween<double>(begin: 0, end: 1).animate(_controller);
_controller.forward();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return CircularProgressIndicator(
strokeWidth: 8,
value: _animationValue.value,
valueColor: _animationColor,
);
},
),
),
);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
}

How to run an animation in loop

I'm shaking a widget using the below code, but the effect is once,
how do I keep it running in a loop at timed intervals. I believe it can be done by changing the key but it's a final and can't be changed.
import 'package:flutter/material.dart';
#immutable
class ShakeWidget extends StatelessWidget {
final Duration duration;
final double deltaX;
final Widget child;
final Curve curve;
const ShakeWidget({
Key key,
this.duration = const Duration(milliseconds: 500),
this.deltaX = 20,
this.curve = Curves.bounceOut,
this.child,
}) : super(key: key);
/// convert 0-1 to 0-1-0
double shake(double animation) =>
2 * (0.5 - (0.5 - curve.transform(animation)).abs());
#override
Widget build(BuildContext context) {
return TweenAnimationBuilder<double>(
key: key,
tween: Tween(begin: 0.0, end: 1.0),
duration: duration,
builder: (context, animation, child) => Transform.translate(
offset: Offset(deltaX * shake(animation), 0),
child: child,
),
child: child,
);
}
}
You need to use AnimationController
And call repeat when the controller is completed
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: ShakeWidget(
child: Text('Hello world'),
),
),
),
);
}
}
class ShakeWidget extends StatefulWidget {
const ShakeWidget({
Key key,
this.duration = const Duration(milliseconds: 500),
this.deltaX = 20,
this.curve = Curves.bounceOut,
#required this.child,
}) : super(key: key);
final Duration duration;
final double deltaX;
final Widget child;
final Curve curve;
#override
_ShakeWidgetState createState() => _ShakeWidgetState();
}
class _ShakeWidgetState extends State<ShakeWidget>
with SingleTickerProviderStateMixin {
AnimationController controller;
#override
void initState() {
super.initState();
controller = AnimationController(
duration: widget.duration,
vsync: this,
)
..forward()
..addListener(() {
if (controller.isCompleted) {
controller.repeat();
}
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
/// convert 0-1 to 0-1-0
double shake(double value) =>
2 * (0.5 - (0.5 - widget.curve.transform(value)).abs());
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (context, child) => Transform.translate(
offset: Offset(widget.deltaX * shake(controller.value), 0),
child: child,
),
child: widget.child,
);
}
}
Use an AnimationController, like so:
AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
)..repeat();
The simple_animations package comes with the LoopAnimation widget which is meant for exactly this. This also means you don't have to create an AnimationController so the code's a lot cleaner.
LoopAnimation(
builder: (context, child, double value) {
return Transform.rotate(
angle: pi * value,
child: const Icon(Icons.notifications),
);
},
duration: const Duration(seconds: 1),
tween: Tween<double>(begin: 0, end: 2),
);
If you want to run an animation forward and backward continuously to get a yo-yo effect, you can use the MirrorAnimation widget instead.
Here is the repeating animation sample, from start → end then from end ← start
#override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: widget.duration);
_animation = widget.tween.animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeIn));
_animationController.forward();
// The looping is done via listener.
_animationController.addListener(() {
if (_animationController.isCompleted) {
_animationController.reverse();
}
if(_animationController.isDismissed){
_animationController.forward();
}
});
}
Don't forget to call _animationController.dispose() in the state's dispose() method.

How to delay list items in flutter?

I am trying to generate a list in flutter which delays every item after some delay.
I was tried using FutureBuilder and AnimatedList but i failed to get it.
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Example(),
);
}
}
class Example extends StatefulWidget {
#override
_ExampleState createState() => new _ExampleState();
}
class _ExampleState extends State<Example> with TickerProviderStateMixin{
AnimationController listViewController;
final Animation listView;
Duration duration = new Duration(seconds: 3);
Timer _timer;
#override
void initState() {
listViewController = new AnimationController(
duration: new Duration(seconds: 2),
vsync: this
);
super.initState();
}
FlutterLogoStyle _logoStyle = FlutterLogoStyle.markOnly;
item() {
_timer = new Timer(const Duration(seconds: 1), () {
return Text("cdscs");
});
}
#override
void dispose() {
listViewController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("hello"),
),
// ListView Builder
body: AnimatedList(
initialItemCount: 10,
itemBuilder: (BuildContext context,
int index,
Animation<double> animation){
return item();
},
)
);
}
}
You could use the AnimationController and an Animation for every child like this example:
class Example extends StatefulWidget {
#override
_ExampleState createState() => new _ExampleState();
}
class _ExampleState extends State<Example> with TickerProviderStateMixin {
AnimationController _animationController;
double animationDuration = 0.0;
int totalItems = 10;
#override
void initState() {
super.initState();
final int totalDuration = 4000;
_animationController = AnimationController(
vsync: this, duration: new Duration(milliseconds: totalDuration));
animationDuration = totalDuration/(100*(totalDuration/totalItems));
_animationController.forward();
}
FlutterLogoStyle _logoStyle = FlutterLogoStyle.markOnly;
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("hello"),
),
// ListView Builder
body: ListView.builder(
itemCount: totalItems,
itemBuilder: (BuildContext context, int index) {
return new Item(index: index, animationController: _animationController, duration: animationDuration);
},
));
}
}
class Item extends StatefulWidget {
final int index;
final AnimationController animationController;
final double duration;
Item({this.index, this.animationController, this.duration});
#override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item> {
Animation _animation;
double start;
double end;
#override
void initState() {
super.initState();
start = (widget.duration * widget.index ).toDouble();
end = start + widget.duration;
print("START $start , end $end");
_animation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: widget.animationController,
curve: Interval(
start,
end,
curve: Curves.easeIn,
),
),
)..addListener((){
setState(() {
});
});
}
#override
Widget build(BuildContext context) {
return Opacity(
opacity: _animation.value,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text("New Sample Item ${widget.index}"),
),
);
}
}
You can change the animation, in this case I was using opacity to simulate fade animation.
Maybe you can Check this response: https://stackoverflow.com/a/59121771/9481448
for (var i = 0; i < fetchedList.length; i++) {
future = future.then((_) {
return Future.delayed(Duration(milliseconds: 100), () {
// add/remove item
});
});