Recreate crossDissolve navigation in Flutter - animation

How can i recreate the modalTransitionStyle = .crossDissolve from iOS when navigating between two pages in Flutter using a Route.

Here you have, you can change the transitionDuration :
Navigator.of(context).push(
PageRouteBuilder<Null>(
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
return Opacity(
opacity: animation.value,
child: YourWidgetPage(),
);
});
},
transitionDuration: Duration(milliseconds: 600)),
);

Related

FadeTransition() widget is animated only once in flutter?

class pin extends StatefulWidget {
#override
_PinState createState() => _PinState();
}
class _PinState extends State<pin> with TickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
bool error = false;
#override
void initState() {
super.initState();
this._controller = AnimationController(
duration: const Duration(milliseconds: 1000), vsync: this);
this._animation =
Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeIn,
));
}
#override
Widget build(BuildContext context) {
if(this.error) {
this.error = false;
_controller.forward();
}
return Container(
child: if (this.error)
Container(
child: FadeTransition(
opacity: _animation,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset("assets/images/sad_face.png"),
),
],
),
),
),
),
}
}
In the above code FadeTransition() widget is animated when the app is first launched.
and the visibility of FadeTransition() is toggled by the error variable.
but when next time the FadeTransition() widget is visible it is not animated?
what is missing, when toggling FadeTransition() the widget should be animated every time it appears!
the error variable is set from outside using Providers and wherever the error is changed the widget is rebuilt, so no need to use setState()
One thing I noticed is error is always false. There is no code to turn it to true and there are two places where it would be set to false. One of them dependent on if it is true (which it will never be since error = true doesn't exist)
That being said, if you want to make your animation run again, where ever you are toggling this property (usually in a button's onTap method) you have to call setState.
In the setState you can either use
controller.forward(from: 0);
// or
controller.reset(); // stops the animation if in progress
controller.forward();

Is there a way in Flutter to show user where to click if he click on wrong btn or widget?

I want to show user correct button or other place to click if he clik on wrong thing, like touch ripples effect or other way...
Im new to flutter and i dont know if is possible to have reference to widget and than call some effect on it...
Dont have code for at this time..
So i need "effect" when user click on "wrong" button right button to flash or some animation signal right button.
Thanks.
Use BottonTheme and animationController
when click this button you use another button's AnimationController
code snippet
ButtonTheme(
minWidth: 88.0 *
_animation
.value, //multiply the static width value with current animation.value value
height: 36.0 *
_animation
.value, //multiply the static height value with current animation.value value
child: RaisedButton(
child: Text('Tap this button to Animate Button on top'),
onPressed: () {
_animationController1
.forward();
},
),
)
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: AnimatingButton(),
);
}
}
class AnimatingButton extends StatefulWidget {
#override
AnimatingButtonState createState() {
return new AnimatingButtonState();
}
}
class AnimatingButtonState extends State<AnimatingButton>
with TickerProviderStateMixin {
//Uses a Ticker Mixin for Animations
Animation<double> _animation;
AnimationController _animationController;
Animation<double> _animation1;
AnimationController _animationController1;
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(
seconds:
2)); //specify the duration for the animation & include `this` for the vsyc
_animation = Tween<double>(begin: 1.0, end: 2.5).animate(
_animationController); //use Tween animation here, to animate between the values of 1.0 & 2.5.
_animation.addListener(() {
//here, a listener that rebuilds our widget tree when animation.value chnages
setState(() {});
});
_animation.addStatusListener((status) {
//AnimationStatus gives the current status of our animation, we want to go back to its previous state after completing its animation
if (status == AnimationStatus.completed) {
_animationController
.reverse(); //reverse the animation back here if its completed
}
});
_animationController1 = AnimationController(
vsync: this,
duration: Duration(
seconds:
2)); //specify the duration for the animation & include `this` for the vsyc
_animation1 = Tween<double>(begin: 1.0, end: 2.5).animate(
_animationController1); //use Tween animation here, to animate between the values of 1.0 & 2.5.
_animation1.addListener(() {
//here, a listener that rebuilds our widget tree when animation.value chnages
setState(() {});
});
_animation1.addStatusListener((status) {
//AnimationStatus gives the current status of our animation, we want to go back to its previous state after completing its animation
if (status == AnimationStatus.completed) {
_animationController1
.reverse(); //reverse the animation back here if its completed
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animating a Button'),
),
body: Column(
children: <Widget>[
Center(
child: ButtonTheme(
minWidth: 88.0 *
_animation1
.value, //multiply the static width value with current animation.value value
height: 36.0 *
_animation1
.value, //multiply the static height value with current animation.value value
child: RaisedButton(
child: Text('Tap this button to Animate Button below '),
onPressed: () {
_animationController
.forward(); // tapping the button, starts the animation.
},
),
),
),
Center(
child: ButtonTheme(
minWidth: 88.0 *
_animation
.value, //multiply the static width value with current animation.value value
height: 36.0 *
_animation
.value, //multiply the static height value with current animation.value value
child: RaisedButton(
child: Text('Tap this button to Animate Button on top'),
onPressed: () {
_animationController1
.forward();
},
),
),
),
],
),
);
}
}

Flutter low framerate performace

I saw linear degradation of framerate UI when I launch speed_dial animation plugin. The problem appear when I add sharedpref function here:
#override
Widget build(BuildContext context) {
sharedpref_function();
return Scaffold(
to listen a saved value, even If the sharedpref is empty I have this degradation.
After 10min whithout doing nothing before, I measure 1120ms/frame when I call _renderSpeedDial
Here is the full code :
bool _dialVisible = true;
Color _speedDial = Colors.pink;
sharedpref_function() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
}
);
}
_renderSpeedDial() {
return SpeedDial(
animatedIcon: AnimatedIcons.add_event,
animatedIconTheme: IconThemeData(size: 22.0),
backgroundColor: _speedDial,
// child: Icon(Icons.add),
/* onOpen: () => print('OPENING DIAL'),
onClose: () => print('DIAL CLOSED'),*/
visible: _dialVisible,
curve: Curves.bounceIn,
children: [
SpeedDialChild(
child: Icon(Icons.fullscreen_exit, color: Colors.white),
backgroundColor: Color(0xffa088df),
onTap: () {
setState(() {
});
},
label: '1',
labelStyle: TextStyle(fontWeight: FontWeight.w500,color: Colors.white),
labelBackgroundColor:Color(0xffa088df),
),
],
);
}
#override
Widget build(BuildContext context) {
sharedpref_function(); // here the sharedpref I use to listen saved value
return Scaffold(
body: Stack(
children: <Widget>[
Padding
(
padding: const EdgeInsets.only(right:10.0, bottom:10.0),
child:
_renderSpeedDial(),
),
],
)
);
}
}
Your sharedpref_function() method is being called inside your build method. That's not recommended at all because it will be called on every frame the UI needs to be rebuild and your code, having an animation there, will be called at 60fps (on every frame).
Move your method inside initState or didChangeDependencies (there're even more methods that get called once or a few times like didChangeDependencies).
When you need to update values, you could do it inside an onTap gesture and that's it.
Also, test your app in --release (release mode) to truly test the speed of your app.

How to animate widget after the app is launched

I want to animate my container height after launching the application (after the widget tree is rendered and shown on screen). For example, animate height from 86 to 210.
What I have tried:
class MyAppState extends State<HomePage> with TickerProviderStateMixin {
double appBarHeight = 86.0;
#override
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => animate());
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
AnimatedContainer(
curve: Curves.fastOutSlowIn,
child: Container(
color: Colors.red,
),
height: appBarHeight,
duration: Duration(milliseconds: 400),
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 16.0, bottom: 16.0),
child: FloatingActionButton(
child: Icon(Icons.brush),
onPressed: () {
animate();
},
),
))
],
),
);
}
void animate(){
setState(() {
if (appBarHeight == 210.0) appBarHeight = 86.0;
else appBarHeight = 210.0;
});
}
}
But it does not work, because widget is animated before appearing on screen. I see white screen while app is launching and then my widget appears on screen with a final height.
In Android for this purpose we can use addOnLayoutChangeListener().
Is there an analogue of addOnLayoutChangeListener() in Flatter?
As you mentioned, looks like it's an issue on Android, I tested on iOS and the animation runs at the beginning.
You can try this workaround :
_startAnimation(_) async {
await Future.delayed(Duration(milliseconds: 200));
animate();
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback(_startAnimation);
}

How to change navigation animation using Flutter

Is there any way to change the default animation when navigating to/from a page in Flutter?
You can use PageRouteBuilder.
The following example shows FadeTransition when you navigate to second screen.
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (_, __, ___) => Page2(),
transitionDuration: Duration(seconds: 2),
transitionsBuilder: (_, a, __, c) => FadeTransition(opacity: a, child: c),
),
);
If you're using go_router:
GoRoute(
path: '/page2',
pageBuilder: (_, state) {
return CustomTransitionPage(
key: state.pageKey,
child: Page2(),
transitionDuration: Duration(seconds: 2),
transitionsBuilder: (_, a, __, c) => FadeTransition(opacity: a, child: c),
);
},
)
and then:
context.go('/page2');
You can subclass MaterialPageRouteand override buildTransitions.
Eg:
class MyCustomRoute<T> extends MaterialPageRoute<T> {
MyCustomRoute({ WidgetBuilder builder, RouteSettings settings })
: super(builder: builder, settings: settings);
#override
Widget buildTransitions(BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
if (settings.isInitialRoute)
return child;
// Fades between routes. (If you don't want any animation,
// just return child.)
return new FadeTransition(opacity: animation, child: child);
}
}
to use :
new RaisedButton(
child: new Text('Goto'),
onPressed: (){
Navigator.push(
context,
new MyCustomRoute(builder: (context) => new SecondPage()),
);
}),
Replace fade transition with your animation
You can achieve this by using CupertinoPageRoute.
Please check the below code.
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Transition Animation Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new FirstPage(),
);
}
}
class FirstPage extends StatefulWidget {
#override
_FirstPageState createState() => new _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('First Page'),
),
body: new Center(
child: new RaisedButton(
child: new Text('Goto Second Page'),
onPressed: () {
Navigator.of(context).push(new SecondPageRoute());
},
),
),
);
}
}
class SecondPageRoute extends CupertinoPageRoute {
SecondPageRoute()
: super(builder: (BuildContext context) => new SecondPage());
// OPTIONAL IF YOU WISH TO HAVE SOME EXTRA ANIMATION WHILE ROUTING
#override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return new FadeTransition(opacity: animation, child: new SecondPage());
}
}
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => new _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Second Page'),
),
body: new Center(
child: new Text('This is the second page'),
),
);
}
}
Some play-around with animation
// OPTIONAL IF YOU WISH TO HAVE SOME EXTRA ANIMATION WHILE ROUTING
#override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return new RotationTransition(
turns: animation,
child: new ScaleTransition(
scale: animation,
child: new FadeTransition(
opacity: animation,
child: new SecondPage(),
),
));
}
I have done this by providing my own builders with custom map in pageTransitionsTheme for the app level theme.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Startup Name Generator Tile',
home: RandomWords(),
theme: new ThemeData(
primaryColor: Colors.white,
// Add the line below to get horizontal sliding transitions for routes.
pageTransitionsTheme: PageTransitionsTheme(builders: {TargetPlatform.android: CupertinoPageTransitionsBuilder(),}),
),
);
}
}
Of course, I didn't add a map entry for ios as I use only android for TargetPlatform.
You can also check out page_transition package from https://pub.dev/packages/page_transition. This package contains the following different transitions.
fade,
rightToLeft,
leftToRight,
upToDown,
downToUp,
scale (with alignment),
rotate (with alignment),
size (with alignment),
rightToLeftWithFade,
leftToRightWithFade
the simplest way I figured, is to use MaterialPageRoute normally just add: fullscreenDialog: true, inside MaterialPageRoute()

Resources