Navigate between screens with transition in Dart - flutter

I have 2 screens and I want to navigate between them with a custom transition (using a library named flutter_spinkit).
How can I go from Page1 to Page2 showing my custom loading screen for 2-3 seconds ?
Here is my code:
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
main() {
runApp(MaterialApp(
home: Page1(),
));
}
class Page1 extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: RaisedButton(
child: Text('Go!'),
onPressed: () {
Navigator.of(context).push(_createRoute());
},
),
),
);
}
}
Route _createRoute() {
return PageRouteBuilder(
// transitionDuration: Duration(seconds: 1),
transitionsBuilder: (context, animation, animationTime, child) {
child = Scaffold(
backgroundColor: Colors.purple[700],
body: Center(
child: SpinKitFadingCube(
color: Colors.white,
size: 100.0,
),
),
);
return ScaleTransition(
scale: animation,
child: child,
alignment: Alignment.center,
);
},
pageBuilder: (context, animation, animationTime) => Page2(),
);
}
class Page2 extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text('Page 2'),
),
);
}
}

Animate when going from One Screen to Another Screen
Your onPressed or onTap method:
InkWell(
onTap: () {
Navigator.of(context).push(_createRoute());
},
)
and then inside your _createRoute method
Route _createRoute() {
return PageRouteBuilder(
transitionDuration: Duration(seconds: 2), //You can change the time here
pageBuilder: (context, animation, secondaryAnimation) => SecondScreen(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
var begin = Offset(1.0, 0.0);
var end = Offset.zero;
var curve = Curves.easeInCirc;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}
with Duration(seconds: 2) you can change the time from microsecond, seconds, minutes, hours
There are many other Curves animations like Curves.easeInCirc, which can be found Here
OR
If you want to use Flutter_Spinkit for showing a type of Animated Loading Indicator than this is how it is done!
Add Dependency:
dependencies:
flutter_spinkit: "^4.1.2"
Then import it in your screen:
import 'package:flutter_spinkit/flutter_spinkit.dart';
and then you can use the Flutter Spinkit Loader where it is required like:
final spinkit = SpinKitFadingCircle(
itemBuilder: (BuildContext context, int index) {
return DecoratedBox(
decoration: BoxDecoration(
color: index.isEven ? Colors.red : Colors.green,
),
);
},
);

I finally got your point. Maybe you just need to change the transitionsBuilder to check the animation is complete or not. I also change the name of SpinKitFadingCube because it should not replace the original child Widget.
transitionsBuilder: (context, animation, animationTime, child) {
final loading= Scaffold(
backgroundColor: Colors.purple[700],
body: Center(
child: SpinKitFadingCube(
color: Colors.white,
size: 100.0,
),
),
);
if(animation.isCompleted){
return child;
}else{
return loading;
}
},

Related

How to implement custom page transition with animation when navigate from one page to another?

I want to achieve below custom animation when navigation from one page to another i am trying with hero animation but no luck any help will appreciated.
Thanks!
I'd take look at this doc https://docs.flutter.dev/cookbook/animation/page-route-animation first.
I'd propose a mix between example shown there of slide-in transition where new page slides from the bottom in your example and mix it with fade-in transition shown here:
import 'package:flutter/material.dart';
import 'list.dart';
import 'main.dart';
class FadeAnimation extends StatelessWidget {
static const routeName = 'Fade_Animation';
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Fade Animation"),
),
body: ListView.builder(
itemCount: curveList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text("${curveList[index]}"),
leading: CircleAvatar(
child: Text("${index + 1}"),
backgroundColor: Colors.white,
),
onTap: () {
print(curveList.length);
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context, animation, anotherAnimation) {
return ReturnPage();
},
transitionDuration: Duration(milliseconds: 2000),
transitionsBuilder:
(context, animation, anotherAnimation, child) {
animation = CurvedAnimation(
curve: curveList[index], parent: animation);
return FadeTransition(
opacity:animation,
child: child,
);
}));
},
),
);
}),
);
}
}
The list.dart file:
import 'package:flutter/animation.dart';
List<Curve> curveList = [
Curves.bounceIn,
Curves.bounceInOut,
Curves.bounceOut,
Curves.decelerate,
Curves.ease,
Curves.easeIn,
Curves.easeInBack,
Curves.easeInCirc,
Curves.easeInCubic,
Curves.easeInExpo,
Curves.easeInOut,
Curves.easeInOutBack,
Curves.easeInOutCirc,
Curves.easeInOutCubic,
Curves.easeInOutExpo,
Curves.easeInOutQuad,
Curves.easeInOutQuart,
Curves.easeInOutQuint,
Curves.easeInOutSine,
Curves.easeInQuad,
Curves.easeInQuart,
Curves.easeInQuint,
Curves.easeInSine,
Curves.easeInToLinear,
Curves.easeOut,
Curves.easeOutBack,
Curves.easeOutCubic,
Curves.easeOutExpo,
Curves.easeOutQuad,
Curves.easeOutQuart,
Curves.easeOutQuint,
Curves.easeOutSine,
Curves.elasticIn,
Curves.elasticInOut,
Curves.elasticOut,
Curves.fastLinearToSlowEaseIn,
Curves.fastOutSlowIn,
Curves.linear,
Curves.linearToEaseOut,
Curves.slowMiddle,
];
Combination of the two should be exactly what you're looking for.
main.dart file:
import 'package:flutter/material.dart';
import 'fadeAnimation.dart';
main() {
runApp(MaterialApp(
routes: {
FadeAnimation.routeName: (context) => FadeAnimation(),
},
theme: ThemeData.dark(),
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
appBar: AppBar(title: Text("Page Tranaction")),
body: ListView.builder(
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: ListTile(
onTap: () {
Navigator.of(context).pushNamed(animationTypeList[index]);
},
leading: CircleAvatar(
backgroundColor: Colors.white,
child: Text("${index + 1}"),
),
title: Text(animationTypeList[index].toString()),
),
),
);
},
itemCount: animationTypeList.length,
),
),
),
));
}
class ReturnPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text('you're here'),
),
);
}
}
var animationTypeList = [
FadeAnimation.routeName,
];
Or instead of combining the 2 during transition wrap widget that contains the next screen with fade-in widget so when it gets created it fades in only once with some internal variable keeping track of that. That way you would have for example: slide-in animation during transition and widget you're transiting to would be opaque at first with gradual fade-in. Or the other way around.
Hope this helps!

Flutter transition like iOS 13 modal full screen

I would like to have the iOS-Modal-Transition where the new screen animates from the bottom and the old screen is being pushed behind. I found this very promising package:
modal_bottom_sheet
This is the function I am using to show the modal:
showCupertinoModalBottomSheet(
expand: true,
context: context,
builder: (context) => Container(
color: AppColors.blue,
),
);
However this is not working a 100% correctly as the view behind is not being pushed in the back.
What am I missing here? Let me know if anything is unclear!
Here is some more of my code:
This is my whole page, from where I would like to have the transition:
class _MonthPageState extends State<MonthPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.secondary,
body: SafeArea(
child: Stack(
children: [
...
Positioned(
bottom: 10,
right: 20,
child: Hero(
tag: widget.month.name + 'icon',
child: AddButton(
onTapped: () {
showCupertinoModalBottomSheet(
expand: true,
context: context,
builder: (context) => Container(
color: AppColors.blue,
),
);
},
),
),
),
],
),
),
);
}
And this is my Router:
class AppRouter {
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialWithModalsPageRoute(
builder: (context) => HomePage(),
);
case '/month':
final Month month = settings.arguments as Month;
return _buildTransitionToMonthPage(month);
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(
child: Text('No route defined for ${settings.name}'),
),
),
);
}
}
static PageRouteBuilder _buildTransitionToMonthPage(Month month) {
return PageRouteBuilder(
transitionDuration: Duration(milliseconds: 450),
reverseTransitionDuration: Duration(milliseconds: 450),
pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return MonthPage(
month: month,
);
},
transitionsBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(opacity: animation, child: child);
},
);
}
}
In order to get that pushing behind animation, you need to use CupertinoScaffold alongside with CupertinoPageScaffold, e.g.
#override
Widget build(BuildContext context) {
return CupertinoScaffold(
transitionBackgroundColor: Colors.white,
body: Builder(
builder: (context) => CupertinoPageScaffold(
backgroundColor: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: ElevatedButton(
child: Text('show modal'),
onPressed: () =>
CupertinoScaffold.showCupertinoModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.white,
builder: (context) => Container(
color: Colors.white,
child: Center(
child: ElevatedButton(
onPressed: () => Navigator.of(context)
.popUntil((route) =>
route.settings.name == '/'),
child: Text('return home'),
),
)),
)),
),
],
),
),
),
);
}

barrierDismissible in showGeneralDialog is not working with Scaffold

I am still new with Flutter. I try to make my dialog to be able to dismiss when click outside of the dialog. However if i use Scaffold, the barrierDismissible:true is not working. I tried to use Wrap but an error : No Material widget found will be displayed. Is there any idea on how to dismiss the dialog?
This is my code:
showGeneralDialog(
barrierDismissible: true,
pageBuilder: (context, anim1, anim2) {
context1 = context;
return StatefulBuilder(
builder: (context, setState) {
return Scaffold(
backgroundColor: Colors.black .withOpacity(0.0),
body: Align(
alignment: Alignment.bottomCenter,
child: Container(
child: InkWell()
)
)
}
}
)
Scaffold is not required to display showGeneralDialog. The Material widget was required in your code because the InkWell widget needs a Material ancestor. You could use any widget that provides material such as Card or Material widget itself. Also barrierLabel cannot be null.
Please see the working code below or you can directly run the code on Dartpad https://dartpad.dev/6c047a6cabec9bbd00a048c972098671
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text("showGeneralDialog Demo"),
),
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () {
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel:
MaterialLocalizations.of(context).modalBarrierDismissLabel,
barrierColor: Colors.black54,
pageBuilder: (context, anim1, anim2) {
return Center(
child: Container(
width: 200,
height: 100,
child: StatefulBuilder(
builder: (context, snapshot) {
return const Card(
color: Colors.white,
child: Center(
child: InkWell(
child: Text(
"Press outside to close",
style: TextStyle(color: Colors.black),
),
),
),
);
},
),
),
);
},
);
},
child: const Text("Show Dialog"));
}
}
For anyone who needs to use a Scaffold in their AlertDialogs (perhaps to use ScaffoldMessenger), here is the simple work around:
Wrap the Scaffold with an IgnorePointer. The "barrierDismissible" value will now work.
#override
Widget build(BuildContext context) {
return IgnorePointer(
child: Scaffold(
backgroundColor: Colors.transparent,
body: AlertDialog(
title: title,
content: SizedBox(
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
child: ListBody(
children: content
),
),
),
actions: actions,
insetPadding: const EdgeInsets.all(24.0),
shape: Theme.of(context).dialogTheme.shape,
backgroundColor: Theme.of(context).dialogTheme.backgroundColor,
)
),
);
}
Add this in showGeneralDialog
barrierLabel: ""
Code will look like this
showGeneralDialog(
barrierDismissible: true,
barrierLabel: "",
pageBuilder: (context, anim1, anim2) {
context1 = context;
return StatefulBuilder(
builder: (context, setState) {
return Scaffold(
backgroundColor: Colors.black .withOpacity(0.0),
body: Align(
alignment: Alignment.bottomCenter,
child: Container(
child: InkWell()
)
)
}
}
)
I was encountering this issue when using showGeneralDialog on top of a map view. The root cause of my issue was that I had wrapped the dialog in a PointerInterceptor.
To fix it, I had to set intercepting to false.
PointerInterceptor(
intercepting: onMap, // false when not an map
child: Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
)
)

how to implement animation textField on two pages in Flutter

How do I implement this kind of animation textField? and also this should be on two pages. (same as a gif). When user click back button/system back button should be back to the previous page.
I got from Facebook app, please check
I found my own answer, I used Hero and PageRouteBuilder
If anyone know a better way, please let me know
class TextScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
Hero(
tag: 'text',
transitionOnUserGestures: true,
child: Material(
type: MaterialType.transparency,
child: IconButton(
onPressed: () {
Navigator.of(context).push(
PageRouteBuilder(
transitionDuration: Duration(milliseconds: 500),
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return NewPage();
},
transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return Align(
child: FadeTransition(
opacity: animation,
child: child,
),
);
},
),
);
},
icon: Icon(
Icons.search,
color: Colors.white,
)),
),
),
],
),
);
}
}
class NewPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Hero(
tag: 'text',
child: Container(
height: 50,
decoration: BoxDecoration(color: Colors.white70, borderRadius: BorderRadius.all(Radius.circular(30))),
child: Material(type: MaterialType.transparency, child: TextField()),
)),
),
);
}
}

Flutter - Hero animation is not working with tab navigator

I am new to flutter and I am using hero widget to make animation for floating button.
I have bottom navigation and I have to open page with tab navigator. But hero animation is not working.
I use every possible solution but still hero animation not working for page route.
Here is my code snippet.
FloatingActionButton(
onPressed: () {
_selectTab(TabItem.Floating);
},
child: Icon(Icons.add),
heroTag: "tag",
),
This is click for fab button to open new page
void _selectTab(TabItem tabItem) {
if (tabItem == currentTab) {
// pop to first route
_navigatorKeys[tabItem].currentState.popUntil((route) => route.isFirst);
} else {
setState(() => currentTab = tabItem);
}
}
In navigator
#override
Widget build(BuildContext context) {
var routeBuilders = _routeBuilders(context);
return Navigator(
observers: [
HeroController(),
],
key: widget.navigatorKey,
initialRoute: TabNavigatorRoutes.root,
onGenerateRoute: (routeSettings) {
return PageRouteBuilder(
transitionDuration: Duration(seconds: 1),
pageBuilder: (_, __, ___) =>
routeBuilders[routeSettings.name](context));
});
}
Route
if (widget.tabItem == TabItem.Floating) {
return ActFloatingScreen(
title: 'Floating Tab',
onPush: (materialIndex) =>
_push(context, materialIndex: materialIndex),
);
}
push
void _push(BuildContext context, {int materialIndex: 500}) {
var routeBuilders = _routeBuilders(context, materialIndex: materialIndex);
Navigator.push(
context,
PageRouteBuilder(
transitionDuration: Duration(seconds: 1),
pageBuilder: (_, __, ___) =>
routeBuilders[TabNavigatorRoutes.detail](context)));
}
and finally my desired class which I want to open with hero animation
return Scaffold(
backgroundColor: Colors.white,
body: Hero(
tag: "tag",
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Container(
color: Colors.green,
height: 200,
),
PositionedDirectional(
start: 0,
end: 0,
top: 150,
child: Center(
child: Icon(
Icons.add,
size: 100,
)),
),
],
),
),
);