I didn't find any example for constructor AnimatedModalBarrier.
Don't know how to use this widget like modalbarrier.
https://api.flutter.dev/flutter/widgets/AnimatedModalBarrier-class.html
const AnimatedModalBarrier({
Key key,
Animation<Color> color,
this.dismissible = true,
this.semanticsLabel,
this.barrierSemanticsDismissible,
}) : super(key: key, listenable: color);
Since AnimatedModalBarrier works by disabling interactions with the widgets behind itself, the common implementation is using a Stack. For example you want to disable interactions with FormWidget, the modal barrier must be placed above the FormWidget
Stack(
alignment: AlignmentDirectional.center,
children: <Widget>[
FormWidget,
_animatedModalBarrier
],
)
To create the AnimatedModalBarrier itself,you need to create an Animation<Color>. You can use ColorTween to create the animation
ColorTween _colorTween = ColorTween(
begin: Color.red
end: Color.blue,
);
AnimationController _animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1)
);
Animation<Color> _colorTweenAnimation = _colorTween.animate(_animationController);
_animatedModalBarrier = AnimatedModalBarrier(
color: _colorTweenAnimation
);
Source & Full Code: https://www.woolha.com/tutorials/flutter-using-animatedmodalbarrier-examples
Related
i created my staggered animation following the official tutorial : https://flutter.dev/docs/development/ui/animations/staggered-animations.
The issue is that the number of ticks the controller goes thought (and thus the frame rate) is low, about 50 fps (it can be even lower in some other exemples i tried).
Is there a way to increase the number of ticks an (animation)Controller goes through, or is there a better solution for this ?
Thanks !
Here's a gif of the laggy widget: https://i.stack.imgur.com/aXdef.gif
==> (StackOverflow does not want me to put images yet, so you got a link instead)
I printed each frame/tick, here's what i got:
flutter: 100.0 -> frame 0
flutter: 100.0 -> frame 1
flutter: 100.32715344429016 -> frame 2
flutter: 100.72060895198956 -> frame 3
...
flutter: 199.6830144248088 -> frame 40
flutter: 200.0 -> frame 41
flutter: 200.0 -> frame 42
flutter: 200.0 -> frame 43
flutter: 200.0 -> frame 44
flutter: 200.0 -> frame 45
flutter: 200.0 -> frame 46
Here is my full code:
class VerificationBox extends StatefulWidget {
#override
_VerificationBoxState createState() => _VerificationBoxState();
}
class _VerificationBoxState extends State<VerificationBox>
with TickerProviderStateMixin {
bool _isOpened = false;
AnimationController _controller;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 1000), vsync: this);
}
Future<void> _playAnimation() async {
try {
_isOpened
? await _controller.reverse().orCancel
: await _controller.forward().orCancel;
} on TickerCanceled {
// the animation got canceled, probably because it was disposed of
}
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
_playAnimation();
_isOpened = !_isOpened;
},
child: StaggerAnimation(controller: _controller.view),
);
}
}
class StaggerAnimation extends StatelessWidget {
StaggerAnimation({Key key, this.controller}):
opacity = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.9,
1,
curve: Curves.linear,
),
),
),
width = Tween<double>(
begin: 100.0,
end: 200.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.0,
0.9,
curve: Curves.easeInOutCirc,
),
),
),
super(key: key);
final AnimationController controller;
final Animation<double> opacity;
final Animation<double> width;
int counter = 0;
Widget _buildAnimation(BuildContext context, Widget child) {
print('${width.value} -> frame $counter');
counter++;
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(35),
color: Colors.green,
),
// curve: Curves.easeInOut,
height: 25,
width: width.value,
// duration: Duration(milliseconds: 500),
child: Row(
children: [
Container(
alignment: Alignment.center,
width: 80,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(35),
color: Colors.red[300],
),
child: Text(
'verification',
style: TextStyle(fontSize: 13),
textAlign: TextAlign.center,
),
),
Expanded(
child: Opacity(
opacity: opacity.value,
child: Text(
'BCDEFG',
textAlign: TextAlign.center,
),
),
)
],
));
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
builder: _buildAnimation,
animation: controller,
);
}
}
TickerProvider provides Ticker which simply means it tells our app that the device has updated the (or screen is updated), so that our AnimationController can generate a new value and we can redraw our widget according to that.
Generally speaking you can't really decide how many times the TickerProvider provides the Ticker. It entirely depends on the device and how many times it can refresh it's screen.
As Flutter Docs States :
Flutter aims to provide 60 frames per second (fps) performance, or 120
fps performance on devices capable of 120Hz updates. For 60fps, frames
need to render approximately every 16ms. Jank occurs when the UI
doesn't render smoothly.
In your case you're running your app on iOS Simulator and possibly in debug mode. Please don't check your app's performance either in debug mode or on a simulator. Use a real device and run you app in release or profile mode to check the real performance of a flutter app.
Launch the app in profile mode as follows:
In Android Studio and IntelliJ, use the Run > Flutter Run main.dart in
Profile Mode menu item. In VS Code, open your launch.json file, and
set the flutterMode property to profile (when done profiling, change
it back to release or debug):
"configurations": [
{
"name": "Flutter",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
}
]
From the command line, use the --profile flag:
$ flutter run --profile
Please visit official flutter docs for more info on performance :
I have some animation code that changes background color infinitely
but the problem is I want to do this without a button trigger
and I want this to be automated at first time (when it's firstly loading)
below is code
I`m so stuck could anyone help please
the purpose is to animate without a trigger, it automatically runs animation that changes background
import 'package:flutter/material.dart';
class ScreenTime extends StatefulWidget {
#override
_ScreenTimeState createState() => _ScreenTimeState();
}
class _ScreenTimeState extends State<ScreenTime> {
List<Color> colorList = [
Colors.red,
Colors.blue,
Colors.green,
Colors.yellow
];
List<Alignment> alignmentList = [
Alignment.bottomLeft,
Alignment.bottomRight,
Alignment.topRight,
Alignment.topLeft,
];
int index = 0;
Color bottomColor = Colors.black54;
Color topColor = Colors.white10;
Alignment begin = Alignment.bottomLeft;
Alignment end = Alignment.topRight;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
AnimatedContainer(
duration: Duration(seconds: 2),
onEnd: () {
setState(() {
index = index + 1;
// animate the color
bottomColor = colorList[index % colorList.length];
topColor = colorList[(index + 1) % colorList.length];
//// animate the alignment
// begin = alignmentList[index % alignmentList.length];
// end = alignmentList[(index + 2) % alignmentList.length];
});
},
decoration: BoxDecoration(
gradient: LinearGradient(
begin: begin, end: end, colors: [bottomColor, topColor])),
),
Positioned.fill(
child: IconButton(
icon: Icon(Icons.play_arrow),
onPressed: () {
setState(() {
bottomColor = Colors.blue;
});
},
),
)
],
));
}
}
To keep as much as your original implementation as possible while fixing the problem, doing
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {bottomColor = Colors.blue;}));
in initState would not pose an issue. This is as long as it's done in initState. Calling it in build would lead to an undesirable extra infinite loop.
However, using an AnimationController on repeat would almost certainly be a cleaner implmentation.
the purpose of this question was basically "how to animate AnimatedContainer without a trigger"
and I think I found a solution
what I did is
just make a new function and then in the build method, invokes the method
and method code is like below
setState(() {
index = index + 1;
bottomColor = Colors.blue;
});
my second solution is this and I think it works
but I worry if it has a any side effects
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
Use this
bool selected = false;
#override
void initState() {
Future.delayed(const Duration(seconds: 1), () {
setState(() {
selected = true;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.white
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedAlign(
alignment: selected ? Alignment.topRight : Alignment.bottomLeft,
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
child: const FlutterLogo(size: 50.0),
),
],
));}
This Will automatically starts the animation. You can change the duration or animation type also.
I built this custom card (from UNO game) which looks something like
I have used a ColorTween to change the boxshadow property of a container over 1 second, with the following code
class SpecialUnoCard extends StatefulWidget {
final String _value;
SpecialUnoCard(this._value);
#override
_SpecialUnoCardState createState() => _SpecialUnoCardState();
}
class _SpecialUnoCardState extends State<SpecialUnoCard>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
int index = 0;
final _listOfTweens = [
ColorTween(begin: red, end: blue),
ColorTween(begin: red, end: green),
ColorTween(begin: red, end: orange),
ColorTween(begin: blue, end: red),
ColorTween(begin: blue, end: green),
ColorTween(begin: blue, end: orange),
ColorTween(begin: green, end: red),
ColorTween(begin: green, end: blue),
ColorTween(begin: green, end: orange),
ColorTween(begin: orange, end: red),
ColorTween(begin: orange, end: green),
ColorTween(begin: orange, end: blue),
];
ColorTween tween() =>
_listOfTweens[Random().nextInt(_listOfTweens.length - 1)];
#override
void initState() {
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_animation = tween()
.chain(CurveTween(curve: Curves.easeInOutCubic))
.animate(_controller);
_controller.addListener(() {
setState(() {});
});
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reverse();
} else if (status == AnimationStatus.dismissed) {
_controller.forward();
}
});
_controller.forward();
super.initState();
}
#override
void deactivate() {
_controller.dispose();
super.deactivate();
}
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(
vertical: _cardMarginVer, horizontal: _cardMarginHor),
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_cardCornerRadii),
border: Border.all(
color: _animation.value, width: 4, style: BorderStyle.solid),
boxShadow: [
BoxShadow(color: _animation.value, spreadRadius: 12, blurRadius: 25)
],
color: Colors.black,
),
child: Container(
height: _cardHeight,
width: _cardWidth,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.black,
),
child: (widget._value == plus4)
? SvgPicture.asset('assets/plus4.svg')
: SvgPicture.asset('assets/wild.svg'),
),
);
}
}
Now, is there a way to animate or shuffle the colors between a bunch of values ? I want some functionality that relates to the following pseudo code
ColorTween(values: <Color>[Colors.orange , Colors.red , Colors.blue , ........]
You could say that I want to chain colors together
I have tried looking up the following post, but did not find what I needed.
How could I change ColorTween colors in Flutter
Thanks for your time!
Try RainbowColor which allows interpolation/tweening among several colors. It provides a multi-color variant of ColorTween exactly as you describe:
RainbowColorTween([Colors.orange, Colors.red, Colors.blue])
It can also be used outside of tween context to interpolate colors across a spectrum, e.g.
var rb = Rainbow(spectrum: [Colors.orange, Colors.red, Colors.blue]);
Color warmColor = rb[0.25];
Color coldColor = rb[0.83];
Btw, good timing. I released RainbowColor just yesterday, and I honestly had no idea you asked this question a few days ago when I made it.
Check out the AnimatedContainer at https://flutter.dev/docs/cookbook/animation/animated-container. It's an easier way to handle animations and I think it has exactly what you're looking for. The test code on the page will let you test it immediately. Just put your decoration and integrate the random values a bit to see the magic. Good luck!
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).
I have an animation where two containers collide with each other. I want the containers to reverse back with animation to their respective starting offset. The containers move along varied paths and duration.
As seen in the animation gif attached the green and red containers collide and jump back to their starting offsets rather than sliding back.
Here is the code I used to make the GIF, in my actual code I'm using rectangle intersection to check when the containers collide.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
List<AnimationController> _controller = List(2);
List<Animation<Offset>> _animation = List(2);
List<Tween<Offset>> tween = List(2);
#override
void initState() {
super.initState();
tween[0] = Tween(begin: Offset(0, 10), end: Offset(200, 10));
tween[1] = Tween(begin: Offset(200, 10), end: Offset(0, 10));
for (int i = 0; i < 2; i++) {
_controller[i] =
AnimationController(vsync: this, duration: Duration(seconds: 1));
_animation[i] = tween[i].animate(_controller[i])
..addListener(
() {
setState(
() {
print(
'${_animation[0].value.dx.toInt()}:${_animation[0].value.dy.toInt()} ${_animation[1].value.dx.toInt()}:${_animation[1].value.dy.toInt()}');
if (((_animation[0].value.dx) / 2).round() ==
((_animation[1].value.dx) / 2).round()) {
_controller[0].stop();
_controller[1].stop();
_controller[0].reset();
_controller[1].reset();
Future.delayed(Duration(milliseconds: 100)).then((_) {
tween[0] = Tween(
begin: Offset(
_animation[0].value.dx, _animation[0].value.dy),
end: Offset(0, 10));
tween[1] = Tween(
begin: Offset(
_animation[1].value.dx, _animation[1].value.dy),
end: Offset(200, 10));
_animation[0] = tween[0].animate(_controller[0]);
_animation[1] = tween[1].animate(_controller[1]);
_controller[0].forward();
_controller[1].forward();
});
}
},
);
},
);
}
WidgetsBinding.instance.addPostFrameCallback(
(_) => _afterLayout(),
);
}
void _afterLayout() {
for (int i = 0; i < 2; i++) {
_controller[i].forward();
}
}
#override
void dispose() {
super.dispose();
for (int i = 0; i < 1; i++) {
_controller[i].dispose();
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("collision"),
),
body: Column(
children: <Widget>[
Expanded(
child: Stack(
children: <Widget>[
Container(
width: double.infinity,
height: double.infinity,
),
Positioned(
left: _animation[0] != null ? _animation[0].value.dx : 0,
top: _animation[0] != null ? _animation[0].value.dy : 0,
child: Container(
width: 50,
height: 50,
color: Colors.red,
),
),
Positioned(
left: _animation[1] != null ? _animation[1].value.dx : 0,
top: _animation[1] != null ? _animation[1].value.dy : 0,
child: Container(
width: 50,
height: 50,
color: Colors.green,
),
),
],
),
),
RaisedButton(
onPressed: () {
_controller[0].reset();
_controller[1].reset();
tween[0] = Tween(begin: Offset(0, 10), end: Offset(200, 10));
tween[1] = Tween(begin: Offset(200, 10), end: Offset(0, 10));
_controller[0].duration = Duration(seconds: 1);
_controller[1].duration = Duration(seconds: 1);
_animation[0] = tween[0].animate(_controller[0]);
_animation[1] = tween[1].animate(_controller[1]);
_controller[0].forward();
_controller[1].forward();
},
child: Text("Animate"),
)
],
),
),
);
}
}
I want the containers to smoothly slide back to their respective starting offsets with animation.
I will add a bit of explanation here to help others maybe.
Animations in flutter are controlled by an AnimationController. You can control one ore more animations using a single AnimationController ( you can use same controller if you want to have animations triggered simultaneously).
Now, to start an animation (or all animations linked to the same controller) you can use forward() method. The forward() method accepts a parameter that specify from which point on should the animation continue, the parameter value is between 0...1.
If you want to do the animation in backwards, the controller has a method called reverse() which will perform the animation in the reverse order. Same, the method accepts a parameter with value from 0 to 1, if no parameter is specified the animation will "reverse" from the last state.
Note in order to have a reverse animation you should not call reset() on the controller. reset() method will set all the values of the controller to the initial ones.