Using SizeTransition to animate in a pageRouteBuilder - flutter

I want to use the SizeTransition animation to animate my page route, but there is no effect when I run it.
Here is my code
Navigator.push(
context,
PageRouteBuilder(
transitionDuration: Duration(seconds: 2),
transitionsBuilder:
(context, animation, animationTime, child) {
return SizeTransition(
sizeFactor: animation,
axis: Axis.vertical,
axisAlignment: 0,
child: child,
);
},
pageBuilder: (context, animation, animationTime) {
return CreateUpdateNoteView();
},
settings: RouteSettings(arguments: note),
),
);
This is the effect I am going for

First of all, we do not have the animation itself so it is kind of hard to say what is missing exactly but 2 things:
even though you put a transition it doesn't mean that the animation itself has a duration so:
building a controller
class YourClass extends State<XXX> with
SingleTickerProviderStateMixin {
late AnimationController controller;
#override
void initState() {
controller = AnimationController(
vsync: this,
duration: const Duration(second: 2),
); // automatically animation will be started
}
then add it in your sizeTransition:
Navigator.push(
context,
PageRouteBuilder(
transitionDuration: Duration(seconds: 2),
transitionsBuilder:
(context, animation, animationTime, child) {
return SizeTransition(
sizeFactor: CurvedAnimation(
curve: Curves.linear,
parent: controller
),
axis: Axis.vertical,
axisAlignment: 0,
child: child,
);
},
pageBuilder: (context, animation, animationTime) {
return CreateUpdateNoteView();
},
settings: RouteSettings(arguments: note),
),
);
A package exist for this exact purpose and is developped by flutter.dev, it is animations (can be found here: https://pub.dev/packages/animations#container-transform) and there is a codelab (can be found here: https://codelabs.developers.google.com/codelabs/material-motion-flutter#4), this will definitely help you.
Hope it could help

Related

How can I animate several widgets at the same time?

Flutter. There are two screens. On the first screen, there is one widget in the center (a container with text). On the second screen (ListView), the same (container with text), but shifted to the side, and another one is added(TextField). How do I animate the transition between these screens? Move the first widget (container) I know how. But how do I add a TextField at the same time ? ......as an option, I thought to apply the opacity of the TextField , but this place on the first screen is already occupied. Probably a complete replacement of the screens is needed here.
Here you have example of quick animation. This code should be in onpressed
Navigator.push(
context,
PageRouteBuilder(
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secAnimation,
Widget child) {
animation = CurvedAnimation(
parent: animation,
curve: Curves.fastLinearToSlowEaseIn);
return ScaleTransition(
scale: animation,
child: child,
alignment: Alignment.center,
);
},
transitionDuration:
const Duration(milliseconds: 300),
pageBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secAnimation) {
return **urpage**();
}));

Flutter showGeneralDialog with Slide and Fade animations

I have the following dialog. It has Slide Transition when it pops up on the screen and when it is being dismissed. Along with it, I also use Fade Transition for the background when dialog is showed or closed.
showGeneralDialog(
barrierDismissible: true,
barrierLabel: '',
barrierColor: kModalBackgroundColor,
transitionDuration: Duration(milliseconds: 150),
pageBuilder: (ctx, anim1, anim2) {
return DismissibleModalWidget();
},
transitionBuilder: (ctx, anim1, anim2, child) {
return SlideTransition(
position: Tween(begin: Offset(0, 1), end: Offset(0, 0)).animate(anim1),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8 * anim1.value, sigmaY: 8 * anim1.value),
child: FadeTransition(
opacity: anim1,
child: child,
),
),
);
},
context: context,
);
Widget DismissibleModalWidget
class DismissibleModalWidget extends StatelessWidget {
const DismissibleModalWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Dismissible(
key: const Key('dismissible'),
direction: DismissDirection.vertical,
onDismissed: (_) => Navigator.of(context).pop(),
child: Material(
.....
What the code does now
SlideTransition works before FadeTransition, meaning that first the dialog will appear on the screen, then the fade transition will start to work. Same when I drag down the dialog to dismiss it, only after the dialog disappeared completely from the screen, fade will start animation from the blurred screen.
What I want to achieve
I would like to make both of these transitions to work together. Meaning as slide animation of the dialog is progress, so is fade transition of the background. When I want to drag down the dialog to dismiss it, the fade will start working and the more I drag down the dialog, the less blurred the background will be so that as soon as dialog completely disappeared, the background is back to normal.

How to animate routes transtion relative to the previous one in flutter

I am trying to achieve something like that coupertino page transition on routing. (briefly how to target and animate both the previous and current routes).
I checked this package page_transition, but the logic used seems off as its rebuilding the previous context widget and tries to hack an animation in the new route.
even in the documentation it seems to only be about the route on top of the navigation stack.
and you end up with something like this:
Navigator.of(context).push(AnimatedRoute(
prevPage: widget, nextPage: Page2()));
class AnimatedRoute extends PageRouteBuilder {
final Widget nextPage;
final Widget prevPage;
AnimatedRoute({this.prevPage, this.nextPage}) : super(
transitionDuration: Duration(milliseconds: 700),
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return nextPage;
},
maintainState: true,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return Material(
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 0.0),
end: const Offset(-0.3, 0.0),
).animate(animation),
child: prevPage,
),
SlideTransition(
position: Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: AnimatedBuilder(
animation: animation,
builder: (c, w) {
return Material(
shadowColor: Colors.black,
// elevation: 10.0 * animation.value,
child: nextPage
);
},
),
)
],
),
);
}
);
}
apart from the rebuild this also doesn't take in account the state of the older widget.
a better way to handle that is appreciated
You can use PageRouteBuilder to be able to handle transition both for the page you are transitioning from and the one you are transitioning to as I explain below:
Note: pageBuilder takes 3 parameters:
context, animation and secondaryAnimation. animation is used when the page is navigated to and secondaryAnimation is used for when the page is navigated from.
Suppose that we have two pages, A and B.
For page A:
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return AnimatedBuilder(
animation: animation,
builder: (context, child) {
return AnimatedBuilder(
animation: secondaryAnimation,
builder: (context, innerChild) {
retrun Transform.scale(
scale: (animation.value - secondaryAnimation.value),
child: A(),
);
},
);
},
);
},
),
);
And for page B:
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return AnimatedBuilder(
animation: animation,
builder: (context, child) {
return AnimatedBuilder(
animation: secondaryAnimation,
builder: (context, child) {
return Transform.translate(
offset: Offset(
1.0 - animation.value,
0.0,
),
child: B(),
);
},
);
},
);
},
),
);
This will lead to a transition like the gif below:
Transition sample
(gif explanation: first page moves out with scaling down and second page comes in like a slide transition)
There are other packages too like you can use getx although it is bloated with features, but still it also has a lot of transition to apply b/w both pages. You can check their source code too if you want.
Also why not you use Cupertino Transition it is great and supported by flutter?

Flutter PageView, can i animate removing items from list?

I'm pretty new to flutter and i'm trying to do some animation on a PageView. to be precise, I want to animate removing an item.
I've tried serveral ways to animate it and apart from a solution, the way how you guys would solve such a problem would also be helpful for my flutter skils.
What I've tried so far:
Animating the padding and opacity
the problem with this is that when i set the padding in the setState in the onLongPress it rebuilds the widget and it overrides the padding again with the active or inactive CardPadding (i think)
Animating the width and height
I just can't seem to get both of these values to work
Animating the viewportFraction on the PageViewController
Would not know how to go about this and if it would be possible to do this only for a specific 'Page'
Below is the (stripped down) code I've written thus far.
class Main extends StatefulWidget {
#override
_MainState createState() => _MainState();
}
class _MainState extends State<Main> {
int activeCard = 0;
EdgeInsets inActiveCardPadding = EdgeInsets.symmetric(vertical: 120.0, horizontal: 20.0);
EdgeInsets activeCardPadding = EdgeInsets.symmetric(vertical: 105.0, horizontal: 10.0);
PageController pageController = PageController(
initialPage: 0,
viewportFraction: 0.8,
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: <Widget>[
PageView.builder(
itemCount: PlantCareApp.plants.length,
controller: pageController,
onPageChanged: (activeCardIndex) {
setState(() {
this.activeCard = activeCardIndex;
});
},
itemBuilder: (context, cardIndex) {
return AnimatedContainer(
padding: (activeCard == cardIndex) ? activeCardPadding : inActiveCardPadding;,
duration: Duration(milliseconds: 250),
child: PlantCard(
PlantCareApp.plants[cardIndex],
onTap: () {
Navigator.pushNamed(context, PlantDetailScreen.route, arguments: PlantCareApp.plants[cardIndex]);
},
onLongPress: () {
setState(() {
//
// ANIMATE OR TRIGGER ANIMATION HERE
//
// do the actual removing
/*
PlantCareApp.plants[cardIndex].remove(); // remove from db
PlantCareApp.plants.removeAt(cardIndex); // remove from List
*/
});
//PlantCareApp.plants[cardIndex].remove();
},
),
);
},
),
],
),
),
);
}
}
Any help will be greatly appreciated! How would you guys tackle a problem like this, or how would you tackle this specific use case.
I guess actually animating viewportFraction would be the nicest because of the adjecent 'Pages' moving toward each other as well?
Thanks!
I'm not certain if this is what you are looking for, but here goes.
One way of doing this is simply using the provided Widgets within Flutter. Two of these will help you out: AnimatedList and Dismissible.
Now, you could do something like this:
// define somewhere
final _animatedListGK = GlobalKey<AnimatedListState>();
// put in a function somewhere
return AnimatedList(
key: _animatedListGK,
padding: const EdgeInsets.all(0),
initialItemCount: PlantCareApp.plants.length,
itemBuilder: (context, index, animation) {
return FadeTransition(
opacity: animation,
child: _buildDismissibleRow(context, index, PlantCareApp.plants[index])
);
}
);
Note: you don't have to use the _animatedListGK global key per se, it depends on whether you can use AnimatedList.of(context) or not. Although it is the easier way.
The _animatedListGK is simply a Global Key that provides access to the AnimatedList so you can perform insertions/removals with animation.
Your dismissible row might look something like:
Widget _buildDismissibleRow(BuildContext context, int index, PlantModel plantModel) {
return Dismissible(
key: ValueKey<String>(plantModel.someKey),
direction: DismissDirection.startToEnd,
background: Container(color: Colors.red),
onDismissed: (direction) {
// You could use:
// AnimatedList.of(context)
_animatedListGK.currentState.removeItem(
index,
(context, animation) => Container(),
duration: Duration.zero
);
},
child: _buildContent(context, index, plantModel)
);
}
You could also do it without a dismissible row or even within the child of the dismissible row (_buildContent() for example). Something similar to:
// You could use:
// AnimatedList.of(context)
_animatedListGK.currentState.removeItem(
index,
(context, animation) {
return FadeTransition(
opacity: CurvedAnimation(parent: animation, curve: Interval(0.5, 1.0)),
child: SizeTransition(
sizeFactor: CurvedAnimation(parent: animation, curve: Interval(0.0, 1.0)),
child: _builContent(context, index, plantModel)
)
);
},
duration: const Duration(milliseconds: 300)
);
Notice how the SizeTransition simply "calls itself" by calling _builContent(context, index, plantModel)? That's how you can animate the row itself (out of existence).
Be sure to watch the videos in the aforementioned documentation pages! They will help understanding certain constructs.
A preview of what the dismissible might look like:
A preview of what the SizedTransition might look like:

Is it possible to change the default animation of showGeneralDialog() in flutter?

I'm trying to customize a showGeneralDialog to show my Transform.scale animation. I'm just wondering if there is a way to change the default animation of the widget to a curved animation?
like a1 and a2 within:
transitionBuilder: (context, a1, a2, widget) {
For example, I would like the Transform.scale to have a bounceIn effect.
Also, could someone please explain the difference between transitionBuilder: (context, a1, a2, widget) {} and pageBuilder: (context, animation1, animation2) {} for the showGeneralDialog widget? And how do I properly use them?
Thanks!
Yes it is possible by override transitionBuilder parameter.
1. Creating New showDialog() method
Commonly, developer uses showDialog to put some dialog that overlays underlying
screen.
In this app, it is convenient to have new method so it can be simply reused
through out our application.
new_dialog.dart
Future<T> showNewDialog<T>(
return showGeneralDialog(
...
transitionDuration: const Duration(milliseconds: 400),
transitionBuilder: _buildNewTransition,
);
}
We only reuse showGeneralDialog() method, and customized its animation-related
parameters : its transitionDuration for Duration and its transitionBuilder
as Animating component.
2. Defining new Animating component
In this demo we create simple animation by wrapping our child widget into
ScaleTransition. Then we defined its curve, rather in curve param only, or
in both of curve and reverseCurve.
new_dialog.dart
Widget _buildNewTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return ScaleTransition(
scale: CurvedAnimation(
parent: animation,
curve: Curves.bounceIn,
reverseCurve: Curves.bounceIn,
),
child: child,
);
}
3. Display our new Dialog
Lastly, we can call this animated dialog anywhere in our app by using this
code :
main.dart
RaisedButton.icon(
icon: Icon(Icons.info_outline),
label: Text("Open Dialog"),
onPressed: () {
showNewDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Bounce In"),
);
},
);
},
),
Repository
you may look repository here. Github
Demo
pageBuilder vs Transition builder
If we take look into DialogRoute definition in Flutter Repo, we can conclude that
each showDialog() method will runs and passing parameters in this sequences :
showDialog
showGeneralDialog
_DialogRoute
PopupRoute
ModalRoute
and so on
...
Take look at buildTransitions method _DialogRoute which return FadeTransition by default.
As I tried, if we put transitionBuilder : null, by calling showGeneralDialog, The App will displays Dialog and still got animated.
return showGeneralDialog(
...,
transitionBuilder: null,
);
Conversely, if we put pageBuilder : null, by calling showGeneralDialog, The App will displays nothing.
return showGeneralDialog(
...,
pageBuilder: null,
transitionBuilder: _buildNewTransition,
);
We may conclude that :
pageBuilder although has some parameters of Animation and
SecondaryAnimation, it is meant for defining Widget to display.
transitionBuilder it is meant for defining animation to be
processed, as Flutter displaying the Dialog