Top level transitions in flutter - dart

I want to create a layout in which I have a BottomNavigationBar that is used to navigate between five top-level views.
I want to have a transition like the one found in the material design guidelines for top-level peer transitions.
Link
First the current view is faded out, then the selected view is faded in. The problem is that flutter doesn't seem to have more than two steps in a tween animation, meaning that I can't change the opacity from 1.0 to 0.0, then back to 1.0 (Like CSS #keyframes).
Does anyone have any idea how I can accomplish this? Should I use something other than Tween?
I've tried using multiple Tween animations and changing what the Opacity widget's opacity value mid-animation, but doing that doesn't even animate.

You have to use a Stack for that. This stack should contain both the widget to fade out and the widget to fade in. Create two Tweens controlled by the same animation controller, one fading out (going from 1.0 to 0.0), one for fading in. Do this in initState() from the state of an stateful widget:
_animationController =
AnimationController(duration: Duration(milliseconds: 500), vsync: this);
_fadeIn = Tween(begin: 0.0, end: 1.0).animate(_animationController);
_fadeOut = Tween(begin: 1.0, end: 0.0).animate(_animationController);
(The State needs to use the mixin TickerProviderStateMixin or SingleTickerProviderStateMixin).
With widget a to fade out and b to fade in, the widget to be returned by your build-method will look like:
Stack(children: [
FadeTransition(
child: a,
opacity: _fadeOut,
),
FadeTransition(
child: b,
opacity: _fadeIn,
)
]);
Eventually you start the animation by calling
_animationController?.reset();
_animationController?.forward();
from your build-method.
Don't forget to dispose the controller from within the dispose-method of your widget's state.
You may want to construct a general purpose fading widget, which would be a stateful widget with the state inheriting some flavor of TickerProviderMixin.
If you want to have such an animation as a routing transition, then look here. The example given there uses slide transitions but it should be easy to replace those with FadeTransitions for fading out and in.
Edit: found the widget AnimatedSwitcher in the Flutter Widget Library, which does exactly what you want. It is the general purpose widget I spoke of.

Related

How to present views above the BottomNavigationBar on a button tap

I've been wondering how to implement a really cool little feature I saw in the Algorand app. I've attached a picture to help illustrate what I mean.
The middle button of the navigation bar at the bottom animates the Send and Receive button onto the view, and then changes it's icon to a cross. These buttons persist when you navigate to other views through the other 4 bottom navigation bar items. And when you click the middle cross button, they disappear.
I tried for a bit to implement this in Flutter. My best attempt was creating my own Bottom Navigation Bar widget for my scaffold, containing the bottom icons and a couple buttons on top, but this seemed really janky. I'm not asking for specific code examples of how to get this done, just rather a point in the right direction of how to do this kind of thing.
Speaking of specific code, their code is actually open source, and the code for the bottom nav bar is here
https://github.com/algorand/algorand-wallet/blob/master/ios/Classes/ViewControllers/Core/Container/TabBar/TabBarController.swift
I've been reading it but unfortunately my Swift is not all that great, working through it line by line. I can make a custom bottom nav bar with Container and Row, and then figure out the onTap behaviours, but it's the presenting two buttons above it that's really blocking me.
Scaffold’s floatingActionButton parameter is exactly what you’re looking for.
Need two buttons? No problem, it doesn’t have to be a FloatingActionButton, it can be any widget, including a Row.
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton.extended(
icon: Icon(Icons.arrow_upward),
label: Text('Send'),
onPressed: (){},
backgroundColor: Colors.redAccent),
Padding(padding: EdgeInsets.symmetric(horizontal: 8)),
FloatingActionButton.extended(
icon: Icon(Icons.arrow_downward),
label: Text('Request'),
onPressed: (){},
backgroundColor: Colors.teal),
]
),
Then to trigger it with a button press, just make it conditional:
bool appear = false;
...
floatingActionButton: appear ? Row(...) : null
Then you can make it appear or disappear by changing the boolean in your button’s onPressed (and don’t forget to call setState).

How to push a full-screen page that stays on top of Flutter BottomNavigationBar

I searched everywhere and could not come up with an answer.
I have a BottomNavigationBar and a FloatingActionButton.
What I am trying to do is pushing a full screen page when the user presses the FloatingActionButton.
This page needs to cover the area of the BottomNavigationBar and previous AppBar since in this new page user is not allowed to go to the other tabs of the BottomNavigationBar.
I came across fullscreenDialog, a property of PageRoute Widget class and got excited but could not get it to exactly work as I wanted it to work(top<->bottom as I will explain later)
This page will have it's own Scaffold and AppBar and is able to push/pop to next screens(inside of it's own navigation tree)
In order to pop this page, the user will press a 'x' button positioned at bottom center of the page.
I want to push/pop this new Page from top<->bottom instead of the usual navigation style which is left<->right (For iOS/Cupertino)
I am familiar with this type of UI from iOS devices(ModalViewController)
So How would we implement the push and pop commands?
Or is there another, better/recommended way to do this?
I had a similar problem, and it was solved with this:
await Navigator.of(context, rootNavigator:true).push( // ensures fullscreen
CupertinoPageRoute(
builder: (BuildContext context) {
return MyWidget();
}
) );
Found at https://stackoverflow.com/a/54017488/247451
You should try MaterialPageRoute with fullscreenDialog prop (docs):
Navigator.of(context).push(new MaterialPageRoute<Null>(
builder: (BuildContext context) {
return new AddEntryDialog();
},
fullscreenDialog: true
));
Might not be the best way in your case, but it will appear above the bottom bar and any other navigation widgets.
Code taken from: https://marcinszalek.pl/flutter/flutter-fullscreendialog-tutorial-weighttracker-ii/

Status bar color when navigating to new screen

I am using following in my build() method of 1st screen to change status bar color and it works fine.
// 1st screen's build() method
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.green),
);
However when I navigate to 2nd screen the 1st screen status bar color appears on the 2nd screen too. And in 2nd screen's build() method, I am using the same code with different color
// 2nd screen's build() method
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.red),
);
I had a similar problem and found the solution. The best way is to use AnnotatedRegion under Scaffold without AppBar (appBar is null) instead of the function SystemChrome.setSystemUIOverlayStyle() to set the system ui color.
Something like:
Scaffold(
body: AnnotatedRegion(
value: SystemUiOverlayStyle(statusBarColor: Colors.red)
child: MyBodyWidget(),
),
);
Btw, the value can be SystemUiOverlayStyle.dark or SystemUiOverlayStyle.light if you only want dark or light overlay instead of a color. Note that statusBarColor only works in Android so far.
Also note that appBar has to be null (absent) for AnnotatedRegion to work. You can write your own MyAppBar widget easily inside MyBodyWidget.
Try setting the 2nd status bar color before doing the Navigator.push to the second screen. Like this
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Colors.red),
);
await Navigator.of(context).push(MaterialPageRoute(
builder: (context) => SecondScreen();
));
From Flutter Docs
Call this API in code whose lifecycle matches that of the desired system UI styles. For instance, to change the system UI style on a new page, consider calling when pushing/popping a new PageRoute.
It has a simple solution.
It is one way of several method.(AnnotatedRegion)
First, top parent page buildcontext in Saffold
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.transparent, <---- transparent.
and 2nd page of 3rd page ...
if Appbar : Appbar( backgroundcolor: Colors.red <---- want color.
if no Appbar : Scaffold( backgroundcolor: Colors.red <---- want color.
This way, if you do a navigation pop, Page status color return the background color of Appbar or the background color of the scaffold.
It's my shortcut and I hope it helps.

What is the significance of the settings variable in MaterialPageRoute?

I have a list of ListTile and whenever I tapped them, a new page will appear. Currently, the new page will slide up (when appearing) and slide down (when removed). I wanted to change the transition animation to Fade.
I've read the solution of that in here then I edited the code from the link and here is the result.
class MyCustomRoute<T> extends MaterialPageRoute<T> {
MyCustomRoute({ WidgetBuilder builder})
: super(builder: builder);
#override
Widget buildTransitions(BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
if (settings.isInitialRoute)
return child;
return new FadeTransition(opacity: animation, child: child);
}
}
The only difference from the link's solution to mine was that I never supplied the "settings" variable to the MaterialPageRoute class.
And here is the part of the code where I've used the Navigator.push:
new ListTile(
onTap: (){
Navigator.push(context, new MyCustomRoute(builder: (context) => new SecondPage("someTitle", "someDescription") ));
},
//The rest of the code goes here
I've tried to run this code and I've never expected that this will run smoothly since I never provided the settings variable to the MaterialPageRoute widget but it ran perfectly.
My question is, is this the right way to do it? or
Should I provide settings for the MaterialPageRoute class?
And also since I didn't provide a settings variable for the MaterialPageRoute class, where did it get its settings? In this part of the code:
if (settings.isInitialRoute)
return child;
I would appreciate any enlightment. Thanks in advance.
The settings are only meant for two things - specifying the name, and letting the route know whether it's the first page to be opened.
The isInitialRoute simply tells the route whether it's the first page to be opened; this is important because you don't want a slide up animation on the very first page.
Since it seems your Custom Route is really only used after the first page, you don't need to worry about this. So you're probably fine ignoring the settings, unless you start to use the page as your first page (and even then, fading in might not be the worst thing).

How to transform child widgets in flutter?

I want animate widgets like the below gif
But whats happening is like the below gif
I just added a color to the container to get a sense of the frame of parent container
How can we make the inner widgets to clip when moving out of parent widget?
I am using Transform to animate like projects.
Please let me know if any more info is required.
If you want your red container to clip overflow, you have to wrap it into a ClipRect.
new ClipRect(
child: new Container(color: Colors.red, child: myAnimationThing),
),

Resources