I use GetX Flutter framework, but want use use AutoRoute for navigation. However, if I use AutoRoute, Get.context
is always null
in my widgets therefore things such as Get.width
cause a crash.
Example/steps to reproduce (uses Flutter 3.13.4):
pubspec.yml
name: testtest
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
# All versions are locked to the version I used when posting this question
environment:
sdk: '3.1.2'
dependencies:
flutter:
sdk: flutter
cupertino_icons: 1.0.2
get: 4.6.6
auto_route: 7.8.3
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: 2.0.0
auto_route_generator: 7.3.1
build_runner:
flutter:
uses-material-design: true
lib/main.dart
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
import 'package:get/get_navigation/src/root/get_material_app.dart';
import 'package:testtest/home_screen.dart';
import 'main.gr.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({super.key});
final _appRouter = AppRouter();
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return GetMaterialApp.router( // (1)
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
routerDelegate: _appRouter.declarativeDelegate(routes: (handler) => [HomeRoute()],), // (2)
routeInformationParser: _appRouter.defaultRouteParser(), // (3)
// home: HomeScreen(), // (4)
);
}
}
@AutoRouterConfig()
class AppRouter extends $AppRouter {
@override
List<AutoRoute> get routes => [
AutoRoute(path: "/HomeRoute", page: HomeRoute.page),
];
}
home_screen.dart
import 'package:auto_route/annotations.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
@RoutePage()
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
double? width = null;
try {
width = Get.width;
}catch(_){}
return Scaffold(
body: SafeArea(child:
Text(
"""Context: ${Get.context?.toString() ?? "null"}
width: ${width ?? "Error"}
""")
),
);
}
}
and don't forget to run code generation for AutoRoute:
flutter packages pub run build_runner build
In the example above, a empty screen with this text will appear:
Context: null
width: Error
because Get.context
was null
and Get.width
caused and exception.
However, If you change GetMaterialApp.router
to GetMaterialApp
on line marked (1), comment out lines (2) and (3) and uncomment line (4), AutoRoute will no longer be used and everything works as expected - Get.context
is no longer null
and Get.width
return correct width.
The reason why Get.context
is null in your AutoRoute
example is because GetX
and AutoRoute
are both navigation libraries, and they conflict with each other when used together.
To fix this, you have two options:
Use GetX for navigation. If you want to use GetX for navigation, then you should remove AutoRoute from your project and use GetX's Get.to()
and Get.back()
methods to navigate between screens.
Use AutoRoute for navigation. If you want to use AutoRoute for navigation, then use AutoRoute's Router()
to navigate between screens.
If you choose to use AutoRoute for navigation, then you will need to use AutoRoute's own context object to access context-aware services. This is because AutoRoute creates its own widget tree, and GetX's Get.context
object will not be available within that widget tree.
To access AutoRoute's context object, you can use the RouteData.context
property. This property is available to all AutoRoute widgets.
Below code is an example of how to use the RouteData.context property to get the screen width in an AutoRoute widget:
import 'package:flutter/material.dart';
import 'package:auto_route/auto_route.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final width = RouteData.of(context).context?.width;
return Scaffold(
body: SafeArea(
child: Text('Screen width: $width'),
),
);
}
}
I hope this helps!