I'm quite new to Flutter and I think I haven't understand all the logic behind the state management with Providers.
I've the following widget:
class App extends StatelessWidget {
List<IconButton> navigationActions(BuildContext context) {
return
Consumer<ApplicationState>(builder: (context, appState, _) {
if (appState.loginState == 'loggedIn') {
return [IconButton(
icon: const Icon(Icons.logout),
tooltip: 'Logout',
onPressed: () {
context.read<ApplicationState>().signOut();
},
)];
}
})
;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FOO'),
actions: navigationActions(context)
),
body: ListView(
.........
)
)
}
And I want to show/hide the AppBar action according to the flag loginState set inside ApplicationState
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => ApplicationState(),
builder: (context, _) => App(),
),
);
}
class ApplicationState extends ChangeNotifier {
ApplicationState() {
init();
}
String _loginState = 'loggedOut';
String get loginState => _loginState;
}
I'm not sure about how to implement the function navigationActions.
Which should be the return type? Since I'm not returning a data in the else branch I'm not sure about how to manage that type.
Maybe there are smarter solution, I don't know yet.. Someone has ever implemented a similar logic with Providers?
navigationActions has to return List<IconButton>, but you are returning the result of Consumer which is a Widget. You can use other methods to get the ApplicationState. Here is example code which does what you want:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ApplicationState extends ChangeNotifier {
String _loginState = 'loggedIn';
set loginState(String state) {
_loginState = state;
}
get loginState => _loginState;
void toggleState() {
if (loginState == 'loggedIn')
loginState = 'loggedOut';
else
loginState = 'loggedIn';
notifyListeners();
}
void signOut() {}
}
class ActionTest extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => ApplicationState(),
child: ActionApp(),
);
}
}
class ActionApp extends StatelessWidget {
List<IconButton> navigationActions(BuildContext context) {
final appState = Provider.of<ApplicationState>(context);
if (appState.loginState == 'loggedIn') {
return [
IconButton(
icon: const Icon(Icons.logout),
tooltip: 'Logout',
onPressed: () {
appState.signOut();
},
)
];
} else {
return [];
}
}
#override
Widget build(BuildContext context) {
final appState = Provider.of<ApplicationState>(context);
return Scaffold(
appBar: AppBar(title: Text('FOO'), actions: navigationActions(context)),
body: Container(),
floatingActionButton: FloatingActionButton(
onPressed: () {
appState.toggleState();
},
child: Icon(appState.loginState == 'loggedIn'
? Icons.toggle_off
: Icons.toggle_on),
),
);
}
}
Related
Although questions with such error messages exist in this site, none solves my problem.
I have a button and on clicking the button, I just need to go to a different screen. But when ever I tap on the screen, the error shows up.
I first setup a route in MaterialApp and then tried to navigate to that route on tapping the button. The full code and the error message are given below:
Code:
import 'livesession1to1.dart';
class NavigationService {
static GlobalKey<NavigatorState> navigatorKey =
GlobalKey<NavigatorState>();
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MaterialApp(
home: CountDownTimer(),
navigatorKey: NavigationService.navigatorKey, // set property// Added by me later from prev project
// initialRoute: "/",
routes: <String, WidgetBuilder> {
'/liveSession1to1': (context) =>LiveSession1to1(),
},
)
);
}// end of main
class CountDownTimer extends StatefulWidget {
const CountDownTimer();
final String? title='';
#override
_CountDownTimerState createState() => _CountDownTimerState();
}
class _CountDownTimerState extends State<CountDownTimer> {
#override
void initState() {
super.initState();
}// end of initstate
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Live Session'),
),
body: Text('Demo Text'),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_button(title: "Go", onPressed: () =>
Navigator.of(context ,rootNavigator: true).pushNamed('/liveSession1to1', arguments: {'room_found': 123 } )
),
],
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
Widget _button({required String title, VoidCallback? onPressed}) {
return Expanded(
child: TextButton(
child: Text(
title,
style: const TextStyle(color: Colors.white),
),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
),
onPressed: onPressed,
));
}
}
Error found:
The following assertion was thrown while handling a gesture:
Could not find a generator for route RouteSettings("/liveSession1to1", {room_found: 123}) in the _WidgetsAppState.
Make sure your root app widget has provided a way to generate
this route.
Generators for routes are searched for in the following order:
For the "/" route, the "home" property, if non-null, is used.
Otherwise, the "routes" table is used, if it has an entry for the route.
Otherwise, onGenerateRoute is called. It should return a non-null value for any valid route not handled by "home" and "routes".
Finally if all else fails onUnknownRoute is called.
Unfortunately, onUnknownRoute was not set.
So how to solve the problem ?
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_it/get_it.dart';
void main() {
locatorSetup();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final _navService = locator<NavigationHandler>();
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
onGenerateRoute: generateRoute,
navigatorKey: _navService.navigatorKey,
// I don't know what your first screen is, so I'm assuming it's a Splash Screen
home: SplashScreen());
}
}
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
#override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
final _navService = locator<NavigationHandler>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
_navService.pushNamed(Routes.LiveSession1to1);
},
child: Text("Go to next page"),
),
));
}
}
class LiveSession1to1 extends StatefulWidget {
const LiveSession1to1({Key? key}) : super(key: key);
#override
State<LiveSession1to1> createState() => _LiveSession1to1State();
}
class _LiveSession1to1State extends State<LiveSession1to1> {
final _navService = locator<NavigationHandler>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
_navService.goBack();
},
child: Text("Go to previous page"),
),
));
}
}
GetIt locator = GetIt.instance;
void locatorSetup() {
locator
.registerLazySingleton<NavigationHandler>(() => NavigationHandlerImpl());
}
Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case Routes.LiveSession1to1:
return _getPageRoute(view: LiveSession1to1(), routeName: settings.name);
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(
child: Text('No route defined for ${settings.name}'),
),
),
);
}
}
PageRoute _getPageRoute({String? routeName, Widget? view}) {
return MaterialPageRoute(
settings: RouteSettings(
name: routeName,
),
builder: (_) => view!,
);
}
class Routes {
static const String LiveSession1to1 = "liveSession1to1";
}
abstract class NavigationHandler {
///Pushes `destinationRoute` route onto the stack
Future<dynamic>? pushNamed(String destinationRoute, {dynamic arg});
///Pushes `destinationRoute` onto stack and removes stack items until
///`lastRoute` is hit
Future<dynamic>? pushNamedAndRemoveUntil(
String destinationRoute, String lastRoute,
{dynamic arg});
///Pushes `destinationRoute` onto stack with replacement
Future<dynamic>? pushReplacementNamed(String destinationRoute, {dynamic arg});
///Pushes `destinationRoute` after popping current route off stack
Future<dynamic>? popAndPushNamed(String destinationRoute, {dynamic arg});
///Pops current route off stack
void goBack();
///Pops routes on stack until `destinationRoute` is hit
void popUntil(String destinationRoute);
///Exits app
void exitApp();
late GlobalKey<NavigatorState> navigatorKey;
}
/// Handles navigation
class NavigationHandlerImpl implements NavigationHandler {
#override
late GlobalKey<NavigatorState> navigatorKey;
/// Constructs a NavigationHandler instance
NavigationHandlerImpl({GlobalKey<NavigatorState>? navigatorKey}) {
this.navigatorKey = navigatorKey ?? GlobalKey<NavigatorState>();
}
NavigatorState? get state => navigatorKey.currentState;
#override
void exitApp() {
SystemChannels.platform.invokeMethod('SystemNavigator.pop');
}
#override
void goBack() {
if (state != null) {
return state!.pop();
}
}
#override
Future? popAndPushNamed(String destinationRoute, {arg}) {
if (state != null) {
return state!.popAndPushNamed(destinationRoute, arguments: arg);
}
}
#override
void popUntil(String destinationRoute) {
if (state != null) {
return state!.popUntil(ModalRoute.withName(destinationRoute));
}
}
#override
Future? pushNamed(String destinationRoute, {arg}) {
if (state != null) {
return state!.pushNamed(destinationRoute, arguments: arg);
}
}
#override
Future? pushNamedAndRemoveUntil(String destinationRoute, String lastRoute,
{arg}) {
if (state != null) {
return state!.pushNamedAndRemoveUntil(
destinationRoute,
ModalRoute.withName(lastRoute),
arguments: arg,
);
}
}
#override
Future? pushReplacementNamed(String destinationRoute, {arg}) {
if (state != null) {
return state!.pushReplacementNamed(destinationRoute, arguments: arg);
}
}
}
I am using ValueListenableBuilder to update my UI based on the data provided to it. I am initializing the ValueNotifier with value. But when I tried to read that value it returns nothing.
This is my Notifier class code:
class AppValueNotifier
{
ValueNotifier<List<Food>> valueNotifier = ValueNotifier([]);
void updateDealsList(List<Food> list)
{
valueNotifier.value=list;
print('DEAL LIST IN CLASS: ${ valueNotifier.value}');
}
List<Food> getDealList()
{
return valueNotifier.value;
}
}
In a separate widget I am initializing the value like this:
class HomeWidgetState extends State<HomeWidget> {
AppValueNotifier appValueNotifier = AppValueNotifier();
.
.
.
assignList(List<Food> dealList)
{
appValueNotifier.updateDealsList(dealList);
}
..
..
.
}
Now in another widget class I am building my UI with this data like this:
AppValueNotifier appValueNotifier = AppValueNotifier();
Widget buildList()
{
return ValueListenableBuilder(
valueListenable: appValueNotifier.valueNotifier,
builder: (context, List<Food> value, widget) {
print(
'DEAL LIST: ${appValueNotifier.getDealList()}');
return DealsWidget(
key: menuItemsKey,
updateList: (oldIndex, newIndex, newList) {},
currentMenu: value,
menuItemNodes: [],
changeCellColor: (color, catid) {},
);
},
);
}
But it is returning empty list instead. Not that list which is being initialized at the start.
Anyone help me what is the issue here:
Thanks in advance
You should be able to initialize your ValueNotifier list either in the constructor or based on an action (i.e. a button click, as shown below). Notice how I'm providing the AppValueNotifier service using the Provider pattern, and one widget triggers the action while a separate widget listens to the changes being made.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
Provider(
create: (context) => AppValueNotifier(),
child: MyApp()
)
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
children: [
TriggerWidget(),
Expanded(
child: MyWidget(),
)
]
),
),
);
}
}
class Food {
final String name;
Food({ required this.name });
}
class AppValueNotifier
{
ValueNotifier<List<Food>> valueNotifier = ValueNotifier([]);
void updateDealsList(List<Food> list)
{
valueNotifier.value = list;
print('DEAL LIST IN CLASS: ${ valueNotifier.value}');
}
List<Food> getDealList()
{
return valueNotifier.value;
}
}
class TriggerWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
AppValueNotifier appValueNotifier = Provider.of<AppValueNotifier>(context, listen: false);
return TextButton(
child: const Text('Add Items!'),
onPressed: () {
appValueNotifier.updateDealsList([
Food(name: 'Food 1'),
Food(name: 'Food 2'),
]);
},
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
AppValueNotifier appValueNotifier = Provider.of<AppValueNotifier>(context, listen: false);
return ValueListenableBuilder(
valueListenable: appValueNotifier.valueNotifier,
builder: (context, List<Food> value, widget) {
var list = value;
return ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return Text(list[index].name);
}
);
},
);
}
}
You get this as output:
Also checkout this Gist you can run on DartPad.dev to check out how it works.
I have a Stream Provider (connected to firebase) that is not working. I am guessing that the problem lies in the fact that I am using a named navigator [Navigator.pushNamed(context, '/route',)]. I guess this makes the 'route' widget to not be the son of the widget that calls it. Let me show it better below.
My app structure is as follows:
My main widget which handles routing and receives the Stream with user authentication (there is no problem here):
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Wrapper(),
routes: {
'/home': (context) => Wrapper(),
'/edit_profile': (context) => UserProfile() //This is where I am having trouble.
}
),
);
}
}
The Wrapper that validates if the user is authenticated and acts accordingly:
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
// return either the Home or Authenticate widget
if (user == null){
return Authenticate();
} else {
return HomeWrapper();
}
}
}
The HomeWrapper which receives the second stream and redirects to the widget I am having trouble with:
class HomeWrapper extends StatefulWidget {
#override
_HomeWrapperState createState() => _HomeWrapperState();
}
class _HomeWrapperState extends State<HomeWrapper> {
String currentBodyName = 'home';
Widget currentBodyWidget = Home();
#override
Widget build(BuildContext context) {
Widget _drawerOptions = Row(
children: [
FlatButton(child: someChild, onPressed: () {Navigator.pushNamed(context, '/edit_profile',);},), //This is the actual call to the navigator.
],
);
return StreamProvider<Map>.value( //This is the problematic Stream!
value: DatabaseService().userDetail,
child: Scaffold(
//Body
body: currentBodyWidget,
//I am simplifying this to show the most important parts
bottomNavigationBar: myBottomNavigationBar(
buttons: <Widget>[
FlatButton(
icon: someIcon,
onPressed: () => _onItemTapped('home'),
),
FlatButton(
icon: otherIcon,
onPressed: () => _onItemTapped('second_screen'),
),
],)
//Drawer
drawer: Drawer(child: _drawerOptions,), //This one has the call to the problematic edit_profile route.
);
}
void _onItemTapped(String newBodyName) {
if (newBodyName != currentBodyName){
setState(() {
currentBodyName = newBodyName;
switch(newBodyName) {
case 'home': {
currentBodyWidget = Home();
}
break;
case 'second_screen': {
currentBodyWidget = SecondScreen();
}
break;
default: {
currentBodyWidget = Home();
}
break;
}
});
}
}
}
Finally the edit_profile route calls the UserProfile Widget which looks like this:
class UserProfile extends StatefulWidget {
#override
_UserProfileState createState() => _UserProfileState();
}
class _UserProfileState extends State<UserProfile> {
#override
Widget build(BuildContext context) {
//This is where the error occurs!!
final userDocument = Provider.of<Map>(context) ?? [];
print(userDocument);
return Scaffold(body: Container());
}
}
This is the error that it throws:
The following ProviderNotFoundError was thrown building UserProfile(dirty, state: _UserProfileState#09125):
Error: Could not find the correct Provider<Map<dynamic, dynamic>> above this UserProfile Widget
Thank you very much!!
Turns out my approach was wrong.
Instead of wrapping the HomeWrapper with the StreamProvider, hoping that it would pass the data to the next route (UserProfile ), what I did was to wrap the UserProfile widget with a StreamProvider, as follows:
(Note: I changed the Map StreamProvider for a UserData StreamProvider.)
class UserProfile extends StatefulWidget {
#override
_UserProfileState createState() => _UserProfileState();
}
class _UserProfileState extends State<UserProfile> {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return StreamBuilder<UserData>(
stream: DatabaseService(uid: user.uid).userData,
builder: (context, snapshot) {
if (snapshot.hasData) {
UserData userData = snapshot.data;
return Scaffold(
body: Container(
//My Widget here
);
} else
return Loading();
});
}
}
This series was very helpful: https://www.youtube.com/playlist?list=PL4cUxeGkcC9j--TKIdkb3ISfRbJeJYQwC
I'm a new in Flutter.
I have a problem with a calling future method in constructor. I create method, that return a classes with widgets depends of selected item. The problem is that I need to call this method several times, the first time to build the body, the second time to update the body on tap. But I see error "type 'Future' is not a subtype of type 'Widget'" If I add the type of void instead Future, it will be executed once to create a body.
Code snippets:
class DataPageState extends State<DataPage> {
....
_tables() async {
if (selectedValue == "a") {
return DataA();
}
if (selectedValue == "b") {
return DataB();
}
if (selectedValue == "c") {
return DataC();
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(...
body: new Stack(children: <Widget>[
_tables(), //errors this //I need to call method this
... new Stack(children: <Widget>[
AnimatedContainer(...),
InkWell(onTap: () => setState(
() {
_tables(); //and this
},
),)])...}
You _tables() function should return some Widget. If you want to build Widget using some async call you can use FutureBuilder.
_tables() can not be async. you have to return Widget instead of Future<widget>.
Here is the demo of of how to add widget on click.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
class Home extends StatefulWidget {
Home({Key key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Widget _add = Container();
test() {
_add = Text("datcdsvcdsvsvdjvkjdsvsa");
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: Container(
child: Stack(
children: <Widget>[
RaisedButton(
color: Colors.amber,
child: Text("Press"),
onPressed: () {
setState(() {
test();
});
},
),
_add,
],
),
),
);
}
}
You probably should just edit the function _tables to make it synchronous.
like this:
Widget _tables() {
if (selectedValue == "a") {
return DataA();
}
if (selectedValue == "b") {
return DataB();
}
if (selectedValue == "c") {
return DataC();
}
}
Nowever, If you have some reason to make _tables asyncronous, then do this:
Tables is a type Future. You need a `futureBuilder` for this.
Stack(children: <Widget>[
FutureBuilder<Widget>(
future: _tables(),
builder: (BuildContext _, snapshot) {
if(snapshot.hasError) { // Error
return const MyErrorWidget(); // You will have to create this widget
} else if(!(snapshot.hasData)) { // Loading
return CircularProgressIndicator();
}/ Loaded without any errors
return snapshot.data; // The widget that was returned;
},
),
// the rest of the widgets in the Stack
]);
Now this won't solve the problem. You will have to add a return type to _tables().
so do this
Future<Widget> _tables() async {
I am below code which given in flutter documentation for page routing
// Within the `FirstRoute` widget
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}
But it provides some animation while pushing and poping route.
For Android, the entrance transition for the page slides the page
upwards and fades it in. The exit transition is the same, but in
reverse.
The transition is adaptive to the platform and on iOS, the page slides
in from the right and exits in reverse. The page also shifts to the
left in parallax when another page enters to cover it. (These
directions are flipped in environments with a right-to-left reading
direction.)
Is there any way to route to next page without any animation?
Edit:
Please check the entire code:
class MyApp extends StatelessWidget {
final routes = <String, WidgetBuilder>{
SecondRoute.tag: (context) => SecondRoute(),
};
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter Routes",
home: new FirstRoute(),
routes: routes,
onGenerateRoute: (routeSettings) {
if (routeSettings.name == SecondRoute.tag)
return PageRouteBuilder(pageBuilder: (_, a1, a2) => SecondRoute());
return null;
},
);
}
}
class FirstRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: RaisedButton(
child: Text('Open route'),
onPressed: () {
Navigator.of(context).pushNamed(SecondRoute.tag);
},
),
),
);
}
}
class SecondRoute extends StatelessWidget {
static String tag = 'second-route';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
For Navigator.push(...)
Navigator.push(
context,
PageRouteBuilder(pageBuilder: (_, __, ___) => SecondRoute()),
)
For Navigator.pushNamed(...)
First, add this to your MaterialApp
MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == '/second')
return PageRouteBuilder(pageBuilder: (_, __, ___) => SecondRoute());
return null;
},
)
And now, you can use:
Navigator.pushNamed(context, '/second');
The animation is performed by MaterialPageRoute. If you don't want it, simple use something else:
Navigator.push(
context,
PageRouteBuilder(pageBuilder: (_, __, ___) => MyRoute()),
)
Replace your MyApp with this.
class MyApp extends StatelessWidget {
final routes = <String, WidgetBuilder>{SecondRoute.tag: (context) => SecondRoute()};
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter Routes",
home: new FirstRoute(),
onGenerateRoute: (routeSettings) {
if (routeSettings.name == SecondRoute.tag)
return PageRouteBuilder(
pageBuilder: (_, a1, a2) => FadeTransition(opacity: a1 ,child: SecondRoute()),
transitionDuration: Duration(seconds: 5),
);
return null;
},
);
}
}
As Flutter is now migrating to Navigator 2.0 for increased support, I would recommend checking out their migration guide on adding a TransitionDelegate to the Navigator. Add an instance of this class to your navigator to achieve the intended result:
import 'package:flutter/widgets.dart';
class NoAnimationTransitionDelegate extends TransitionDelegate<void> {
#override
Iterable<RouteTransitionRecord> resolve({
List<RouteTransitionRecord> newPageRouteHistory,
Map<RouteTransitionRecord, RouteTransitionRecord> locationToExitingPageRoute,
Map<RouteTransitionRecord, List<RouteTransitionRecord>> pageRouteToPagelessRoutes,
}) {
final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];
for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
// Renames isEntering to isWaitingForEnteringDecision.
if (pageRoute.isWaitingForEnteringDecision) {
pageRoute.markForAdd();
}
results.add(pageRoute);
}
for (final RouteTransitionRecord exitingPageRoute in locationToExitingPageRoute.values) {
// Checks the isWaitingForExitingDecision before calling the markFor methods.
if (exitingPageRoute.isWaitingForExitingDecision) {
exitingPageRoute.markForRemove();
final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
if (pagelessRoutes != null) {
for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
pagelessRoute.markForRemove();
}
}
}
results.add(exitingPageRoute);
}
return results;
}
}
aidan marshal's solution is simple and works fine but there some adjustments in his code
import 'package:flutter/widgets.dart';
class NoAnimationTransitionDelegate extends TransitionDelegate<void> {
#override
Iterable<RouteTransitionRecord> resolve({
required List<RouteTransitionRecord> newPageRouteHistory,
required Map<RouteTransitionRecord?, RouteTransitionRecord>
locationToExitingPageRoute, required Map<RouteTransitionRecord?,
List<RouteTransitionRecord>> pageRouteToPagelessRoutes}) {
{
final List<RouteTransitionRecord> results = <RouteTransitionRecord>[];
for (final RouteTransitionRecord pageRoute in newPageRouteHistory) {
// Renames isEntering to isWaitingForEnteringDecision.
if (pageRoute.isWaitingForEnteringDecision) {
pageRoute.markForAdd();
}
results.add(pageRoute);
}
for (final RouteTransitionRecord exitingPageRoute in locationToExitingPageRoute.values) {
// Checks the isWaitingForExitingDecision before calling the markFor methods.
if (exitingPageRoute.isWaitingForExitingDecision) {
exitingPageRoute.markForRemove();
final List<RouteTransitionRecord>? pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute];
if (pagelessRoutes != null) {
for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
pagelessRoute.markForRemove();
}
}
}
results.add(exitingPageRoute);
}
return results;
}
}
}