Flutter transition like iOS 13 modal full screen - flutter

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'),
),
)),
)),
),
],
),
),
),
);
}

Related

Flutter implementing custom BottomSheet

Like with awesome bottom sheet of Telegram i would like to have that in our application, i tired to implementing that, but unfortunately i don't have more experience about that and i can implement below code like with that which it doesn't have more feature.
here i attached some Gif images such as what features i want to have them on our application:
opening animation:
switch between tabs animation:
expand and collapsing animation:
preventing closing bottom sheet during dragging down:
Full code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isLong = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Sample'),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: _onPressed,
child: Text('open'),
)
],
),
),
);
}
_onPressed() {
setImages();
Navigator.of(context).push(TransparentRoute(builder: (context) => NewWidget(images)));
}
List<String> images =[];
void setImages() {
images = List.generate(
isLong ? 5 : 25,
(_) => 'http://placeimg.com/100/100/any',
);
}
}
class NewWidget extends StatefulWidget {
const NewWidget(this.images, {Key? key}) : super(key: key);
final List<String> images;
#override
_NewWidgetState createState() => _NewWidgetState();
}
class _NewWidgetState extends State<NewWidget> {
bool isBig = false;
bool isBouncing = true;
final double topOffset = 200;
final double miniHandleHeight = 20;
double safeAreaPadding = 0;
double? startBigAnimationOffset;
double? startStickyOffset;
double backgroundHeight = 0;
double get savedAppBarHeight => safeAreaPadding + kToolbarHeight;
final ScrollController controller = ScrollController();
#override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback(_afterLayout);
super.initState();
}
void _afterLayout(_) {
var media = MediaQuery.of(context);
safeAreaPadding = media.padding.top;
startBigAnimationOffset = topOffset - savedAppBarHeight;
startStickyOffset = (startBigAnimationOffset! + 10);
backgroundHeight = media.size.height - miniHandleHeight - topOffset;
controller.addListener(scrollListener);
}
void scrollListener() {
var offset = controller.offset;
if (offset < 0) {
goOut();
} else if (offset < startBigAnimationOffset! && isBig || offset < startStickyOffset!) {
setState(() {
isBig = false;
});
} else if (offset > startBigAnimationOffset! && !isBig || offset > startStickyOffset!) {
setState(() {
isBig = true;
});
}
if (offset < topOffset && !isBouncing) {
setState(() => isBouncing = true);
} else if (offset > topOffset && isBouncing) {
setState(() => isBouncing = false);
}
}
void goOut() {
controller.dispose();
Navigator.of(context).pop();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: /*isStack ? Colors.white : */Colors.transparent,
body: Stack(
children: [
ListView(
padding: EdgeInsets.zero,
physics: isBouncing ? BouncingScrollPhysics() : ClampingScrollPhysics(),
controller: controller,
children: <Widget>[
Container(
alignment: Alignment.bottomCenter,
height: topOffset,
child: TweenAnimationBuilder(
tween: Tween(begin: 0.0, end: isBig ? 1.0 : 0.0),
duration: Duration(milliseconds: 200),
child: Align(
alignment: Alignment.topCenter,
child: Padding(
padding: EdgeInsets.only(top: 10),
child: Container(
height: 5,
width: 60,
),
),
),
builder: (_, number, child) {
return Container(
height: savedAppBarHeight * (number as double) + miniHandleHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.vertical(
top: Radius.circular((1 - number) * 50),
),
color: Colors.white,
),
child: Opacity(opacity: 1 - (number), child: child),
);
}),
),
Container(
padding: EdgeInsets.all(5),
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height - savedAppBarHeight,
),
decoration: BoxDecoration(
color: Colors.white,
),
child: getGrid(),
)
],
)
],
),
),
);
}
Widget getGrid() {
return GridView.count(
crossAxisSpacing: 10,
mainAxisSpacing: 10,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 3,
children: widget.images.map((url) {
return Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.blueAccent,
),
),
child: Image(
image: NetworkImage(url),
),
);
}).toList(),
);
}
}
class TransparentRoute extends PageRoute<void> {
TransparentRoute({
required this.builder,
RouteSettings? settings,
}) : super(settings: settings, fullscreenDialog: false);
final WidgetBuilder builder;
#override
bool get opaque => false;
#override
Color? get barrierColor => null;
#override
String? get barrierLabel => null;
#override
bool get maintainState => true;
#override
Duration get transitionDuration => Duration(milliseconds: 350);
#override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
final result = builder(context);
return Container(
color: Colors.black.withOpacity(0.5),
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 1),
end: Offset.zero,
).animate(CurvedAnimation(
parent: animation,
curve: Curves.easeIn,
)),
child: result,
),
);
}
}
Here is the outline, with which you can try to implement it. If you feel difficulty, feel free to ask for more suggestions. IMHO, this is not very challenging to implement (but of course need some time to adjust the fine details into what you want).
Firstly, you mentioned animations many times. Have a look at the official guide here: https://flutter.dev/docs/development/ui/animation. For example, if we want to implement the "opening animation" and the "switch between tabs animation" (and other similar things), we want a Container (or other widgets) to have a size changing with time as the animation goes. There are many ways to implement this, as is suggested in the link provided above. For example, we may use AnimatedContainer directly - it even has a video explaining this here. You can also use explicit animations or other things.
Secondly, as for the animating icons, you may use Lottie https://lottiefiles.com/ to create whatever complex animation as you like. Its flutter plugin is here: https://pub.dev/packages/lottie.
Thirdly, as for "preventing closing bottom sheet during dragging down", I will suggest the following: ListView(children: [Container(height:300,color:Colors.black), ...your_real_children...]). Then when dragging down it will not be closed, but only show a header of at most 300 height.
Lastly, you are not restricted to use showModalBottomSheet or things like that. Indeed, when using flutter, you are completely free. So you can just do Navigator.push and draw whatever widget you like without the constraints that modal bottom sheet gives you. Personally, I suggest that you first start with showModalBottomSheet, then when it does not satisfy your needs, you just directly copy its source code and do whatever modifications as you needed. In short, use something in Flutter, and when you need more control, copy the source code and modify it.
You can be helped from this link https://pub.dev/packages/modal_bottom_sheet
import 'package:example/modals/circular_modal.dart';
import 'package:example/web_frame.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'modals/floating_modal.dart';
import 'modals/modal_complex_all.dart';
import 'modals/modal_fit.dart';
import 'modals/modal_inside_modal.dart';
import 'modals/modal_will_scope.dart';
import 'modals/modal_with_navigator.dart';
import 'modals/modal_with_nested_scroll.dart';
import 'modals/modal_with_scroll.dart';
import 'modals/modal_with_page_view.dart';
import 'examples/cupertino_share.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
title: 'BottomSheet Modals',
builder: (context, Widget? child) => WebFrame(
child: child!,
),
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialWithModalsPageRoute(
builder: (_) => MyHomePage(title: 'Flutter Demo Home Page'),
settings: settings);
}
return MaterialPageRoute(
builder: (context) => Scaffold(
body: CupertinoScaffold(
body: Builder(
builder: (context) => CupertinoPageScaffold(
backgroundColor: Colors.white,
navigationBar: CupertinoNavigationBar(
transitionBetweenRoutes: false,
middle: Text('Normal Navigation Presentation'),
trailing: GestureDetector(
child: Icon(Icons.arrow_upward),
onTap: () => CupertinoScaffold
.showCupertinoModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => Stack(
children: <Widget>[
ModalWithScroll(),
Positioned(
height: 40,
left: 40,
right: 40,
bottom: 20,
child: MaterialButton(
onPressed: () => Navigator.of(
context)
.popUntil((route) =>
route.settings.name == '/'),
child: Text('Pop back home'),
),
)
],
),
)),
),
child: Center(child: Container()),
),
),
),
),
settings: settings);
},
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
body: CupertinoPageScaffold(
backgroundColor: Colors.white,
navigationBar: CupertinoNavigationBar(
transitionBetweenRoutes: false,
middle: Text('iOS13 Modal Presentation'),
trailing: GestureDetector(
child: Icon(Icons.arrow_forward),
onTap: () => Navigator.of(context).pushNamed('ss'),
),
),
child: SizedBox.expand(
child: SingleChildScrollView(
primary: true,
child: SafeArea(
bottom: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text('Cupertino Photo Share Example'),
onTap: () => Navigator.of(context).push(
MaterialWithModalsPageRoute(
builder: (context) => CupertinoSharePage()))),
section('STYLES'),
ListTile(
title: Text('Material fit'),
onTap: () => showMaterialModalBottomSheet(
expand: false,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ModalFit(),
)),
ListTile(
title: Text('Bar Modal'),
onTap: () => showBarModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ModalInsideModal(),
)),
ListTile(
title: Text('Avatar Modal'),
onTap: () => showAvatarModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ModalInsideModal(),
)),
ListTile(
title: Text('Float Modal'),
onTap: () => showFloatingModalBottomSheet(
context: context,
builder: (context) => ModalFit(),
)),
ListTile(
title: Text('Cupertino Modal fit'),
onTap: () => showCupertinoModalBottomSheet(
expand: false,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ModalFit(),
)),
section('COMPLEX CASES'),
ListTile(
title: Text('Cupertino Small Modal forced to expand'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ModalFit(),
)),
ListTile(
title: Text('Reverse list'),
onTap: () => showBarModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) =>
ModalInsideModal(reverse: true),
)),
ListTile(
title: Text('Cupertino Modal inside modal'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ModalInsideModal(),
)),
ListTile(
title: Text('Cupertino Modal with inside navigation'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ModalWithNavigator(),
)),
ListTile(
title:
Text('Cupertino Navigator + Scroll + WillPopScope'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ComplexModal(),
)),
ListTile(
title: Text('Modal with WillPopScope'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => ModalWillScope(),
)),
ListTile(
title: Text('Modal with Nested Scroll'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
builder: (context) => NestedScrollModal(),
)),
ListTile(
title: Text('Modal with PageView'),
onTap: () => showBarModalBottomSheet(
expand: true,
context: context,
builder: (context) => ModalWithPageView(),
)),
SizedBox(
height: 60,
)
],
),
),
),
),
),
),
);
}
Widget section(String title) {
return Padding(
padding: EdgeInsets.fromLTRB(16, 20, 16, 8),
child: Text(
title,
style: Theme.of(context).textTheme.caption,
));
}
}
another helpful link [https://pub.dev/packages/draggable_bottom_sheet][2]

Flutter navigation how to move to the second page for each item

I have navigation in my main.dart
class Homescreen extends StatefulWidget {
#override
_Home createState() => _Home();
}
class _Home extends State<Homescreen> {
double xOffset = 0;
double yOffset = 0;
double scaleFactor = 1;
bool isDrawerOpen = false;
#override
Widget build(BuildContext context) {
return AnimatedContainer(
transform: Matrix4.translationValues(xOffset, yOffset, 0)
..scale(scaleFactor),
duration: Duration(milliseconds: 250),
color: Colors.grey[200],
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 50,
),
// Main homescreen view
Container(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (context, index) {
return Container(
child: Column(
children: [
Container(
padding: EdgeInsets.all(15),
margin: EdgeInsets.only(left: 20),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: shadowList,
borderRadius: BorderRadius.circular(10)),
child: GestureDetector(
child: Image.asset(
categories[index]['iconPath'],
height: 50,
width: 50,
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Names()),
);
},
)),
Text(categories[index]['name']),
],
),
);
}),
),
);
}
}
Below is my configuration.dart file which has the menu items and icons
Color primaryGreen = Color(0xff416d6d);
List<BoxShadow> shadowList = [
BoxShadow(color: Colors.grey, blurRadius: 30, offset: Offset(0, 10))
];
List<Map> categories = [
{'name': 'Prayer times', 'iconPath': 'images/prayer.jpg'},
{'name': 'Nearby Mosque', 'iconPath': 'images/nearby.jpg'},
{'name': 'Zakar Calculator', 'iconPath': 'images/calculator.png'},
{'name': 'Islamic Calender', 'iconPath': 'images/islamic.png'},
{'name': 'Tasbeh', 'iconPath': 'images/tasbeh.png'}
];
I added below functionality to move the page to the next page but in a single page it working but I want to move for all the pages so, how would I configure my below code to move on to the each different pages.
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Names()),
);
},
)),
I got that by adding the following code in the top of the page
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Homescreen2(),
initialRoute: '/home',
routes: {
//first route
categories[0]['route']: (context) => PrayTimes(),
categories[1]['route']: (context) => Nearby(),
categories[2]['route']: (context) => Quran(),
categories[3]['route']: (context) => Qibla(),
categories[4]['route']: (context) => Six(),
categories[5]['route']: (context) => Pop(),
categories[6]['route']: (context) => Names(),
categories[7]['route']: (context) => NamesM(),
categories[8]['route']: (context) => Live(),
categories[9]['route']: (context) => Naats(),
categories[10]['route']: (context) => Cards(),
categories[11]['route']: (context) => Duaa(),
categories[12]['route']: (context) => Zakat(),
categories[13]['route']: (context) => Community(),
// Text(categories[0]['name']),// second route
},
);
}
}

Navigate between screens with transition in Dart

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;
}
},

Flutter, how to call Dialog function from another class

what is the proper way to call Dialog function from another class.
I have been searching this topic for a while but seems none of them are my answer.
my Dialog has a little complicated logic for server communicating and some paginations
so this code is going to be long for just one dart file. so I want to separate them.
and I need the some dialog animations so I picked the showGeneralDialog()
I also saw the example dialog implementaion using StatefulBuilder() which can use setState,
but this problem is it is not able to use initState()
for now, what I did is below
dart1 file
import 'package:aaa/bbb/some_dialog_file.dart'
as someDialog;
GestureDetector(
onTap: () async{
var result =
await someDialog.displayDialogOKCallBack(
context,
);
},
child: Container(
width: 60,
height: 60,
child: Icon(
Icons.comment,
size: 38,
),
),
)
dart2 file
Future<dynamic> displayDialogOKCallBack(BuildContext context) async {
return await showGeneralDialog(
barrierLabel: "Label",
barrierDismissible: true,
// barrierColor: ,
transitionDuration: Duration(milliseconds: 400),
context: context,
pageBuilder: (context, anim1, anim2) {
return StatefulBuilder(builder: (context, setState) {
return Scaffold(
body: SafeArea(
),
);
});
},
transitionBuilder: (context, anim1, anim2, child) {
return SlideTransition(
position:
Tween(begin: Offset(0, 1), end: Offset(0, -0.02)).animate(anim1),
child: child,
);
},
);
}
so my question is I want to build very clean animation dialog
which is logically separated from base class file and it has to have initState(), and setState()
how could I acheive this ? thanks
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
onPressed: () {
someDialog(context);
},
child: Text("click"),
),
);
}
Future<dynamic> someDialog(BuildContext context) async {
return await showGeneralDialog(
barrierLabel: "Label",
barrierDismissible: true,
context: context,
pageBuilder: (context, anim1, anim2) {
return Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
// List
AnotherClassDialog(),
],
),
],
),
),
),
);
});
}
}
class AnotherClassDialog extends StatefulWidget {
#override
_AnotherClassDialogState createState() => _AnotherClassDialogState();
}
class _AnotherClassDialogState extends State<AnotherClassDialog> {
Color color;
#override
void initState() {
// TODO: implement initState
super.initState();
color = Colors.black;
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
RaisedButton(
onPressed: () {
setState(() {
color = Colors.red;
});
},
),
Container(
width: 100,
height: 100,
color: color,
),
RaisedButton(
onPressed: () {
setState(() {
color = Colors.green;
});
},
)
],
),
);
}
}
I use a custom dialog in my app in some classes and had the same problem.
You should define a dialog and pass context and other variables to it and call it everywhere you want.
You can define a dialog like this :
showCustomDialog(BuildContext context, String title, String description) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
title,
textAlign: TextAlign.right,
),
content: SingleChildScrollView(
child: Text(
description,
style: Theme.of(context).textTheme.bodyText1,
textAlign: TextAlign.right,
),
),
actions: [
FlatButton(
child: Text(
'ok',
style: Theme.of(context).textTheme.bodyText2.copyWith(
color: Theme.of(context).accentColor,
),
),
onPressed: () => Navigator.of(context).pop(),
),
],
actionsPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
);
});
}
and use it everywhere you want like this :
InkWell(
child: Icon(
Icons.error_outline,
size: 17,
),
onTap: () => showCustomDialog(context,"text1" , "text2") ,
),
I hope my answer will help you.

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,
)),
),
],
),
),
);