Flutter - how use "non-linear" animation with LinearProgressIndicator? - flutter

I using LinearProgressIndicator in my app. I need use "non-linear" animation with LinearProgressIndicator. I need the indicator to move unevenly (a little slower a little faster).
This my current code:
controller = AnimationController(
vsync: this,
upperBound: 1,
animationBehavior: AnimationBehavior.preserve,
duration: Duration(seconds: widget.duration),
);
....
controller.addListener(() {
setState(() {
.....
});
});
....
LinearProgressIndicator(value: controller.value);
this works fine but is "linear"
I tried:
TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0.0, end: 2),
duration: const Duration(milliseconds: 3500),
builder: (context, value, _) => LinearProgressIndicator(
value: value,
),)
but it doesn't give "non-linear" animation. how do i get "non-linear" animation for LinearProgressIndicator ? is it possible?

Related

Flutter animations error, The method '[]' can't be unconditionally invoked because the receiver can be 'null'

I am very new to flutter.
I am having trouble with fixing this error.
return ControlledAnimation(
delay: Duration(milliseconds: (500 * delay).round()),
duration: tween.duration,
tween: tween,
child: child,
builderWithChild: (context, child, animation) => Opacity(
opacity: animation["opacity"],
child: Transform.translate(
offset: Offset(0, animation["translateY"]),
child: child
),
),
);
and the error is
The method '[]' can't be unconditionally invoked because the receiver can be 'null'.
Try making the call conditional (using '?.') or adding a null check to the target ('!'). at the animation["opacity"] line.
Can somebody please help
Complete code
import 'package:flutter/material.dart';
import 'package:simple_animations/simple_animations.dart';
class FadeAnimation extends StatelessWidget {
final double delay;
final Widget child;
FadeAnimation(this.delay, this.child);
#override
Widget build(BuildContext context) {
final tween = MultiTrackTween([
Track("opacity").add(Duration(milliseconds: 500), Tween(begin: 0.0, end: 1.0)),
Track("translateY").add(
Duration(milliseconds: 500), Tween(begin: -30.0, end: 0.0),
curve: Curves.easeOut)
]);
return ControlledAnimation(
delay: Duration(milliseconds: (500 * delay).round()),
duration: tween.duration,
tween: tween,
child: child,
builderWithChild: (context, child, animation) => Opacity(
//opacity: animation.["opacity"],
opacity: animation!(["opacity"]),
child: Transform.translate(
// offset: Offset(0, animation.["translateY"]),
offset: Offset(0, animation?["translateY"] ?? 0),
child: child
),
),
);
}
}
Flutter supports what's called sound null safety. This helps you ensure values aren't null, and thereby prevents some runtime errors. You can read up on it here:
https://dart.dev/null-safety/understanding-null-safety
In this case, I think it's caused by your object named animation, likely a map of some sort. In this case, the compiler is not sure whether or not the animation object is null or not. There's two things you can do: If you're certain animation is never gonna be null, you can tell that by adding a !:
Offset(0, animation!["translateY"]),
Or alternatively, if you think it might be null, you can tell that by adding a ?:
Offset(0, animation?["translateY"]),
But this will replace the translateY value with null if animation is null.
In this case, it might be wise to define a default value to use when it resolves to null, using the ?? operator:
Offset(0, animation?["translateY"] ?? 0),
If you want to know more I advise you to read up on the dart.dev website or look up a helpful video or Medium post.

How to add some delay between AnimationController.repeat() in Flutter

I need to add some delay between each iteration of animation gets call to repeat. Something like the following image.
I tried to do it by passing value to the period parameter of the repeat method but it was not what I expected.
_controller = AnimationController(vsync: this, duration: widget.period)
..addStatusListener((AnimationStatus status) {
if (status != AnimationStatus.completed) {
return;
}
_count++;
if (widget.loop <= 0) {
//_controller.repeat(period: Duration(microseconds: 5000));
_controller.repeat();
} else if (_count < widget.loop) {
_controller.forward(from: 0.0);
}
});
I've also tried to add Tween with the animation. That didn't help either. Can you help me clarify where I went wrong?
AnimatedBuilder(
animation: Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.5, 1.0)
),
),
child: widget.child,
builder: (BuildContext context, Widget child) => _Shiner(
child: child,
direction: widget.direction,
gradient: widget.gradient,
percent: _controller.value,
enabled: widget.enabled,
),
);
Thanks to #pskink Now it's working as I expected. All you have to do is repeat the controller yourself instead of trying to add delay to controller.repeat()
_controller.addStatusListener((status) {
if(status == AnimationStatus.completed){
Future.delayed(Duration(milliseconds: 5000),(){
if(!mounted){
_controller.forward(from: 0.0);
}
});
}
}

How to make animation in flutter

I am trying to slide the logo to right and again come from left
enter image description here
I tried this but it bounces back the logo
void initState() {
super.initState();
_controller = AnimationController(
// duration: const Duration(seconds: 90),
vsync: this,
)..repeat(reverse: false);
_offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(7.1, 7.0),
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeOutQuint,
));
}
You can try below code to slide the logo to right and again come from left,
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_offsetAnimation = Tween<Offset>(
begin: Offset(-1.0,0.0), // You can change starting position as per your require.
end: const Offset(1.0, 0.0), // You can change ending position as per your require.
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.linear, // You can change animation curve per your require.
));
}
(Refer the Curves class to choose other curves).

How to spin widget form one to another angle over Y-axis in flutter?

I want to spin widget from 270 degreee(intially) to 360 degreee. I tried AnimationController with AnimatedBuilder with Transform, but not able to understand how to build and what lowerbound and uppperbound parameter do.
Here is sample
Inside initState
_controller = AnimationController(
value: 50,
animationBehavior: AnimationBehavior.normal,
duration: const Duration(milliseconds: 800),
vsync: this)
..addListener(() {
print(rotate.value.toString());
setState(() {});
});
rotate = Tween<double>(begin: 0, end: 90).animate(_controller);
Animated Builder is
AnimatedBuilder(
animation: rotate,
builder: (context, child) {
return Transform(
origin: Offset(100,100),
child: getChild(context, percent),
transform: Matrix4.identity()..rotateY(rotate.value/100),
);
},
)
It always rotate 360 degree n number of times. I am not able to understand how it working?

Flutter Scrollcontroller maxScrollExtent doesn't go till the end of list

it stops before last element in list. Is there a way to go till the end container of the last element
controller
..animateTo(
controller.position.maxScrollExtent,
curve: Curves.easeIn,
duration: const Duration(milliseconds: 300),
);
});```
Using Without Animation Solved the Problem
Timer(Duration(milliseconds: 500), () {
controller.jumpTo(controller.position.maxScrollExtent);
});
I think this is the best function to scroll to bottom with a good animation
scrollToBottom() {
if (_chatController.hasClients) {
Future.delayed(const Duration(milliseconds: 500)).then((value) {
_chatController.animateTo(
_chatController.position.maxScrollExtent,
duration: const Duration(milliseconds: 200),
curve: Curves.fastOutSlowIn,
);
});
}
}
In my case the problem was that the elements were not equal in size and the size was not known until rendered. So, the ListView scrolled to its initial estimated maxScrollExtent but while scrolling the elements were rendered and the new maxScrollExtent was bigger. I hacked it by giving it a much bigger value initially:
attachmentsScrollController.animateTo(
attachmentsScrollController.position.maxScrollExtent * 2,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut);
I had same problem with CustomeScrollView widget, and I solved with this.
CustomScrollView(
controller: Get.find<ChatController>(tag: 'chatDetail')
.scrollController
.value,
reverse: true,
keyboardDismissBehavior:
ScrollViewKeyboardDismissBehavior.onDrag,
physics: ClampingScrollPhysics(),
cacheExtent: 99999, // <-- here !!! ADD THIS CODE
slivers: [
ChatList(
isQuestion: isQuestion,
postCreatedAt: postCreatedAt,
title: title,
),
],
),
my scroll function was normal as we talked before.
void chatScrollUp() async {
await scrollController.value.animateTo(
scrollController.value.position.maxScrollExtent,
duration: Duration(
milliseconds:
(scrollController.value.position.maxScrollExtent / 2).round()),
curve: Curves.easeOutCirc);}
What worked with me is this:
void scrollAnimateToEnd(ScrollController controller) {
Future.delayed(const Duration(milliseconds: 400)).then((_) {
try {
controller
.animateTo(
controller.position.maxScrollExtent,
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
)
.then((value) {
controller.animateTo(
controller.position.maxScrollExtent,
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
);
});
} catch (e) {
print('error on scroll $e');
}
});
}