So, I'm trying to make a home delivery app for a restaurant in flutter and I can't seem to get my hero animation working. First I made a splash screen where the logo shows up and then it navigates to home page where the logo is supposed to do a hero transition. The splash screen and the home page are in two separate dart files. Here's the code for my splash screen:
import 'package:flutter/material.dart';
import 'home_page.dart';
import 'dart:async';
class Splash extends StatefulWidget {
#override
_SplashState createState() => new _SplashState();
}
class _SplashState extends State<Splash> with SingleTickerProviderStateMixin
{
Animation<double> _mainLogoAnimation;
AnimationController _mainLogoAnimationController;
#override
void initState() {
super.initState();
goToHomePage();
_mainLogoAnimationController = new AnimationController(duration: new Duration(milliseconds: 2500) ,vsync: this);
_mainLogoAnimation = new CurvedAnimation(parent:
_mainLogoAnimationController, curve: Curves.easeIn);
_mainLogoAnimation.addListener(() => (this.setState(() {})));
_mainLogoAnimationController.forward();
}
Future goToHomePage() async {
await new Future.delayed(const Duration(milliseconds: 4000));
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new HomePage()));
}
#override
Widget build(BuildContext context) {
return new Material(
color: Colors.black,
child: new Center(
child: new Opacity(
opacity: 1.0 * _mainLogoAnimation.value,
child: new Hero(
tag: 'tbh_logo',
child: new Image(
image: new AssetImage('assets/images/tbh_main_logo.png'),
width: 300.0
)
)
)
)
);
}
}
And here's the code for the home page:
import 'package:flutter/material.dart';
import '../ui/drawer.dart';
import 'splash.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("The Barni House"),
backgroundColor: Colors.black,
),
drawer: new Drawer(child: MyDrawer()),
body: new Center(
child: Column(
children: <Widget>[
new Container(
child: new Hero(
tag: 'tbh_logo',
child: new Image(
image: new AssetImage('assets/images/tbh_main_logo.png'),
width: 300.0
)
)
)
],
)
),
);
}
}
Checked your code so the hero animation is working but its happening to fast because of the transition duration is only 300 milliseconds.
To achieve the below result you can make a Custom MaterialPageRoute.
Before
#override
Duration get transitionDuration => const Duration(milliseconds: 300);
After
#override
Duration get transitionDuration => const Duration(milliseconds: 1000);
Also, you can play with the CurvedAnimation
new CurvedAnimation(
parent: routeAnimation,
curve: Curves.elasticIn,
)
CustomRoute.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
final Tween<Offset> _kBottomUpTween = new Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
);
// Offset from offscreen to the right to fully on screen.
final Tween<Offset> _kRightMiddleTween = new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
);
// Offset from offscreen below to fully on screen.
class AppPageRoute extends MaterialPageRoute<String> {
#override
final bool maintainState;
#override
final WidgetBuilder builder;
CupertinoPageRoute<String> _internalCupertinoPageRoute;
AppPageRoute({
#required this.builder,
RouteSettings settings: const RouteSettings(),
this.maintainState: true,
bool fullscreenDialog: false,
}) : assert(builder != null),
assert(settings != null),
assert(maintainState != null),
assert(fullscreenDialog != null),
super(
settings: settings,
fullscreenDialog: fullscreenDialog,
builder: builder,
) {
assert(opaque); // PageRoute makes it return true.
}
#override
Color get barrierColor => null;
#override
Duration get transitionDuration => const Duration(milliseconds: 1000);
CupertinoPageRoute<String> get _cupertinoPageRoute {
assert(_useCupertinoTransitions);
_internalCupertinoPageRoute ??= new CupertinoPageRoute<String>(
builder: builder,
fullscreenDialog: fullscreenDialog,
hostRoute: this,
);
return _internalCupertinoPageRoute;
}
bool get _useCupertinoTransitions {
return _internalCupertinoPageRoute?.popGestureInProgress == true ||
Theme.of(navigator.context).platform == TargetPlatform.iOS;
}
#override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
final Widget result = builder(context);
assert(() {
if (result == null) {
throw new FlutterError('The builder for route "${settings.name}" returned null.\n'
'Route builders must never return null.');
}
return true;
}());
return result;
}
#override
Widget buildTransitions(
BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
if (_useCupertinoTransitions) {
return _cupertinoPageRoute.buildTransitions(context, animation, secondaryAnimation, child);
}
return new _CustomPageTransition(routeAnimation: animation, child: child, fullscreenDialog: fullscreenDialog);
}
}
class _CustomPageTransition extends StatelessWidget {
final Animation<Offset> _positionAnimation;
final Widget child;
final bool fullscreenDialog;
_CustomPageTransition({
Key key,
#required Animation<double> routeAnimation,
#required this.child,
#required this.fullscreenDialog,
}) : _positionAnimation = !fullscreenDialog
? _kRightMiddleTween.animate(new CurvedAnimation(
parent: routeAnimation,
curve: Curves.elasticIn,
))
: _kBottomUpTween.animate(new CurvedAnimation(
parent: routeAnimation, // The route's linear 0.0 - 1.0 animation.
curve: Curves.elasticIn,
)),
super(key: key);
#override
Widget build(BuildContext context) {
return new SlideTransition(
position: _positionAnimation,
child: child,
);
}
}
Push new Route
Future goToHomePage() async {
await new Future.delayed(const Duration(milliseconds: 4000));
Navigator.of(context).push(new AppPageRoute(builder: (BuildContext context) => new HomePage()));
}
You can use Custom MaterialPageRoute for the splash screen and for other routes MaterialPageRoute.
Hope it helps
// main.dart class
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;
import 'package:flutter_test7/photo_hero.dart';
import 'package:flutter_test7/second_page.dart';
class HeroAnimation extends StatelessWidget {
Widget build(BuildContext context) {
timeDilation = 2.5; // 1.0 means normal animation speed.
return new Scaffold(
appBar: new AppBar(
title: const Text('Basic Hero Animation'),
),
body: new Center(
child: new PhotoHero(
photo: 'images/flippers-alpha.png',
width: 300.0,
onTap: () {
Navigator.of(context).pushNamed('/second_page');
},
),
),
);
}
}
void main() {
runApp(
new MaterialApp(
home: new HeroAnimation(),
routes: <String, WidgetBuilder>{
'/second_page': (context) => new SecondPage()
},
),
);
}
// photo_hero.dart class
import 'package:flutter/material.dart';
class PhotoHero extends StatelessWidget {
const PhotoHero({Key key, this.photo, this.onTap, this.width})
: super(key: key);
final String photo;
final VoidCallback onTap;
final double width;
Widget build(BuildContext context) {
return new SizedBox(
width: width,
child: new Hero(
tag: photo,
child: new Material(
color: Colors.transparent,
child: new InkWell(
onTap: onTap,
child: new Image.asset(
photo,
fit: BoxFit.contain,
),
),
),
),
);
}
}
// second_page.dart class
import 'package:flutter/material.dart';
import 'package:flutter_test7/photo_hero.dart';
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: const Text('Flippers Page'),
),
body: new Container(
color: Colors.lightBlueAccent,
padding: const EdgeInsets.all(16.0),
alignment: Alignment.topLeft,
child: new PhotoHero(
photo: 'images/flippers-alpha.png',
width: 100.0,
onTap: () {
Navigator.of(context).pop();
},
),
),
);
}
}
Hope this helps.
Hero animation is quite easy to implement in Flutter. You just need to import the package package:flutter/scheduler.dart in your landing page. See below code
import 'package:flutter/scheduler.dart' show timeDilation;
Remember to add timeDilation variable and assign it a value to speed up or slow down the animation in seconds. Add these just after your build method as in example below
Widget build(BuildContext context) {
timeDilation = 2;
For better animation, just use a custom animation
Related
I am quite new to app development and I had a few questions about Flutter I was hoping someone could help me with!
First, I am trying to code an intro-slide part in my code. I have found this code online (https://flutterawesome.com/simple-and-configurable-app-introduction-slider-for-flutter/) and when I tried executing it, using my own images, only the background color seems to print. When I remove the background colors, it is just a white screen. Is my pageImage part correct? I saved an assert folder everywhere, so I'm unsure if that is the problem. I have included my code at the end.
Thank you for your time!
class _MyHomePageState extends State<MyHomePage> {
List<Slide> slides = new List();
#override
void initState() {
super.initState();
slides.add(
new Slide(
title: "ERASER",
description: "Allow miles wound place the leave had. To sitting subject no improve studied limited",
pathImage: "assets/images/1.png",
backgroundColor: Colors.pink[200],
),
);
slides.add(
new Slide(
title: "PENCIL",
description: "Ye indulgence unreserved connection alteration appearance",
pathImage: "assets/images/1.png",
backgroundColor: Colors.blue[200],
),
);
slides.add(
new Slide(
title: "RULER",
description:
"Much evil soon high in hope do view. Out may few northward believing attempted. Yet timed being songs marry one defer men our. Although finished blessing do of",
pathImage: "assets/images/3.jpg",
),
);
}
void onDonePress() {
// TODO: go to next screen
}
void onSkipPress() {
// TODO: go to next screen
}
#override
Widget build(BuildContext context) {
return new IntroSlider(
slides: this.slides,
onDonePress: this.onDonePress,
onSkipPress: this.onSkipPress,
);
}
}
**Solution: edit assets in pubspec page
Edit:
On the left (the orange part) is how I want the blue image to appear: No scrolling and fills the whole page. However, I tried to make my image (on the right) fill the page by editing the width and height and I started having to scroll where there is the pink background below and above the image (I assume it is because it keeps having to center the image).
Is there any way to make my image my background so it is like the picture on the left? I understand the orange color background is the background color, but hopefully, by comparing the two it makes sense. Thank you!
I create new intro widget. Here is the code.
import 'package:flutter/material.dart';
class MyIntroView extends StatefulWidget {
final List<Widget> pages;
final VoidCallback onIntroCompleted;
const MyIntroView({
Key key,
#required this.pages,
#required this.onIntroCompleted,
}) : assert(pages != null),
assert(onIntroCompleted != null),
super(key: key);
#override
_MyIntroViewState createState() => _MyIntroViewState();
}
class _MyIntroViewState extends State<MyIntroView> {
PageController _pageController;
int _currentPage = 0;
#override
void initState() {
_pageController = PageController(
initialPage: _currentPage,
);
super.initState();
}
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
NotificationListener<ScrollEndNotification>(
onNotification: (x) {
setState(() {
_currentPage = _pageController.page.round();
});
return false;
},
child: PageView(
children: widget.pages,
controller: _pageController,
),
),
Align(
alignment: Alignment.bottomCenter,
child: _buildBottomButtons(),
),
],
);
}
bool get _isFinalPage => _currentPage == widget.pages.length - 1;
Widget _buildBottomButtons() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Opacity(
opacity: _isFinalPage ? 0.0 : 1.0,
child: _buildButton("SKIP", _gotoLastPage),
),
_buildNavIndicator(),
_isFinalPage
? _buildButton("DONE", widget.onIntroCompleted)
: _buildButton("NEXT", _gotoNextPage),
],
),
);
}
Widget _buildButton(String title, VoidCallback callback) {
return FlatButton(
child: Text(
title,
style: TextStyle(color: Colors.white),
),
onPressed: callback,
);
}
void _gotoLastPage() {
_pageController.animateToPage(
widget.pages.length - 1,
duration: const Duration(milliseconds: 600),
curve: Curves.ease,
);
}
void _gotoNextPage() {
_pageController.nextPage(
duration: const Duration(milliseconds: 600),
curve: Curves.easeInOut,
);
}
Widget _buildNavIndicator() {
final indicatorList = <Widget>[];
for (int i = 0; i < widget.pages.length; i++)
indicatorList.add(_buildIndicator(i == _currentPage));
return Row(children: indicatorList);
}
Widget _buildIndicator(bool isActive) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isActive ? Colors.white : Colors.white30,
),
child: SizedBox(width: 8, height: 8),
),
);
}
}
Usage:
import 'package:flutter/material.dart';
import 'package:flutter_app_test3/my_intro_view.dart';
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MyIntroView(
pages: <Widget>[
Image.asset("assets/images/1.png", fit: BoxFit.cover),
Image.asset("assets/images/2.png", fit: BoxFit.cover),
Image.asset("assets/images/3.jpg", fit: BoxFit.cover),
],
onIntroCompleted: () {
print("Into is Completed");
//To the navigation stuff here
},
);
}
}
Ask me if you have any doubts in the comment
just try wrapping your Widget into Scaffold Widget and return
#override
Widget build(BuildContext context) {
return Scaffold(body:IntroSlider(
slides: this.slides,
onDonePress: this.onDonePress,
onSkipPress: this.onSkipPress,
));
}
I was facing the same issue and I fixed it by setting fit:Boxfit.fill for the image.
Is it possible to edit image like to rotate and to add text over image. Is there any plugin for that? I need an editor for image to add texts with various fonts and colors. Thank you
you should use RepaintBoundary to capture it as a widget and to overlap widget use stack.
Look at this code how to capture widget as a image.
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey _globalKey = new GlobalKey();
bool inside = false;
Uint8List imageInMemory;
Future<Uint8List> _capturePng() async {
try {
print('inside');
inside = true;
RenderRepaintBoundary boundary =
_globalKey.currentContext.findRenderObject();
ui.Image image = await boundary.toImage(pixelRatio: 3.0);
ByteData byteData =
await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
// String bs64 = base64Encode(pngBytes);
// print(pngBytes);
// print(bs64);
print('png done');
setState(() {
imageInMemory = pngBytes;
inside = false;
});
return pngBytes;
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return RepaintBoundary(
key: _globalKey,
child: new Scaffold(
appBar: new AppBar(
title: new Text('Widget To Image demo'),
),
body: SingleChildScrollView(
child: Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'click the button below to capture image',
),
new RaisedButton(
child: Text('capture Image'),
onPressed: _capturePng,
),
inside ? CircularProgressIndicator()
:
imageInMemory != null
? Container(
child: Image.memory(imageInMemory),
margin: EdgeInsets.all(10))
: Container(),
],
),
),
)),
);
}
}
I am trying to display all the phone gallery images myself by reading the external files directory and possibly every image that ends with jpg or png. I achieved that, but could not display all of them in a grid as due to their sizes or the no. of images, the app crashes. Code looks bit like this..
new GridView.count(
shrinkWrap: true,
physics: new ClampingScrollPhysics(),
crossAxisCount: 2,
// children: new List<Widget>.generate(_images.length, (index) {
// children: new List<Widget>.generate(allImages.length, (index) {
children: new List<Widget>.generate(_PhoneImages.length, (index) {
File imgFile = _phoneImageFiles[index];
thumbBytes = _phoneThumbBytes[index]; // assuming it got created!!!
// print('thumbbytes $thumbBytes');
print('phone image index: $index');
return new GridTile(
child: new GestureDetector(
child: new Stack(
children: [
new Card(
// color: Colors.blue.shade200,
color: Colors.white70,
child: new Center(
// child: new Text('tile $index'),
// child: new Image.asset(_images[index]),
/*
child: new CachedNetworkImage(
imageUrl: allImages[index].path,
// placeholder: new CircularProgressIndicator(),
errorWidget: new Icon(Icons.error),
)
*/
child: new Image.file(imgFile,
// child: new Image.memory(thumbBytes,
So I tried the imageresize library which tells me to do a heavy operation of resizing, that takes almost 20 minutes before I can show the thumbnails.
All I need is to read thumbnails from gallery like how the phone gallery displays. I don't need categorization. I need all and a link to their full version so that I can do something with them later on.
I think this might help multi_image_picker
e.g
import 'package:flutter/material.dart';
import 'package:multi_image_picker/asset.dart';
class AssetView extends StatefulWidget {
final int _index;
final Asset _asset;
AssetView(this._index, this._asset);
#override
State<StatefulWidget> createState() => AssetState(this._index, this._asset);
}
class AssetState extends State<AssetView> {
int _index = 0;
Asset _asset;
AssetState(this._index, this._asset);
#override
void initState() {
super.initState();
_loadImage();
}
void _loadImage() async {
await this._asset.requestThumbnail(300, 300); // here requesting thumbnail
setState(() {});
}
#override
Widget build(BuildContext context) {
if (null != this._asset.thumbData) {
return Image.memory(
this._asset.thumbData.buffer.asUint8List(),
fit: BoxFit.cover,
);
}
return Text(
'${this._index}',
style: Theme.of(context).textTheme.headline,
);
}
}
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:multi_image_picker/asset.dart';
import 'package:multi_image_picker/multi_image_picker.dart';
import 'asset_view.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Asset> images = List<Asset>();
String _error;
#override
void initState() {
super.initState();
}
Widget buildGridView() {
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
return AssetView(index, images[index]);
}),
);
}
Future<void> loadAssets() async {
setState(() {
images = List<Asset>();
});
List resultList;
String error;
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
);
} on PlatformException catch (e) {
error = e.message;
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
images = resultList;
if (error == null) _error = 'No Error Dectected';
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: <Widget>[
Center(child: Text('Error: $_error')),
RaisedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: buildGridView(),
)
],
),
),
);
}
}
I'm looking for a way to implement Marquee style on a Text widget so that it automatically start scrolling when the text is overflowed from the screen.
Is there a way to do it.
I've tried all the decoration modes but cant seem to find a Marquee option there.
This widget is what I came up with, and I think it serves your needs:
class MarqueeWidget extends StatefulWidget {
final Widget child;
final Axis direction;
final Duration animationDuration, backDuration, pauseDuration;
const MarqueeWidget({
Key? key,
required this.child,
this.direction = Axis.horizontal,
this.animationDuration = const Duration(milliseconds: 6000),
this.backDuration = const Duration(milliseconds: 800),
this.pauseDuration = const Duration(milliseconds: 800),
}) : super(key: key);
#override
_MarqueeWidgetState createState() => _MarqueeWidgetState();
}
class _MarqueeWidgetState extends State<MarqueeWidget> {
late ScrollController scrollController;
#override
void initState() {
scrollController = ScrollController(initialScrollOffset: 50.0);
WidgetsBinding.instance.addPostFrameCallback(scroll);
super.initState();
}
#override
void dispose() {
scrollController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: widget.child,
scrollDirection: widget.direction,
controller: scrollController,
);
}
void scroll(_) async {
while (scrollController.hasClients) {
await Future.delayed(widget.pauseDuration);
if (scrollController.hasClients) {
await scrollController.animateTo(
scrollController.position.maxScrollExtent,
duration: widget.animationDuration,
curve: Curves.ease,
);
}
await Future.delayed(widget.pauseDuration);
if (scrollController.hasClients) {
await scrollController.animateTo(
0.0,
duration: widget.backDuration,
curve: Curves.easeOut,
);
}
}
}
}
Its functionality should be pretty obvious. An example implementation would look like this:
class FlutterMarqueeText extends StatefulWidget {
const FlutterMarqueeText({Key? key}) : super(key: key);
#override
_FlutterMarqueeTextState createState() => _FlutterMarqueeTextState();
}
class _FlutterMarqueeTextState extends State<FlutterMarqueeText> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Flutter Marquee Text"),
),
body: const Center(
child: SizedBox(
width: 200.0,
child: MarqueeWidget(
direction: Axis.horizontal,
child: Text("This text is to long to be shown in just one line"),
),
),
),
);
}
}
Use The Marquee package.
and if you get any 'hasSize' Error or 'Incorrect uses of Parent Widget' Error..
Just wrap Marquee widget with container and give height and width of that container.
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()