Here is where I instantiate my MaterialApp:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'My New App';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
initialRoute: '/special',
routes: {
'/special': (context) => const SpecialPage(),
'/another': (context) => const AnotherPage()
});
}
}
The pages are very similar. Here is the Special page:
class SpecialPage extends StatelessWidget {
const SpecialPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Special Stuff'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/another');
},
child: const Text('Special Content Goes Here'),
),
),
);
}
When I try to compile I get the error: Null check operator used on a null value. Why?
The error message indicates the problem occurs in the construction of MaterialApp.
Remove the const in the build method of MyApp
Like so:
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
initialRoute: '/special',
routes: {
'/special': (context) => const SpecialPage(),
'/another': (context) => const AnotherPage()
});
}
Related
import 'package:flutter/material.dart';
import 'package:routemaster/routemaster.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
late final RoutemasterDelegate _routerDelegate = RoutemasterDelegate(
routesBuilder: (context) => RouteMap(
routes: buildRoutingTable(
routerDelegate: _routerDelegate,
),
),
);
#override
Widget build(BuildContext context) => MaterialApp.router(
title: 'Flutter Demo',
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.lightGreenAccent,
),
routeInformationParser: const RoutemasterParser(),
routerDelegate: _routerDelegate,
);
}
Map<String, PageBuilder> buildRoutingTable({
required RoutemasterDelegate routerDelegate,
}) =>
{
PathConstants.tabContainerPath: () => MaterialPage(
name: 'first-screen',
child: FirstScreen(
onNavigate: () => routerDelegate.replace(
_PathConstants.secondScreen,
),
),
),
PathConstants.secondScreen: () => const MaterialPage(
name: 'second-screen',
child: SecodScreen(),
),
};
class _PathConstants {
const PathConstants.();
static String get tabContainerPath => '/';
static String get secondScreen => '${tabContainerPath}second-screen';
}
class FirstScreen extends StatelessWidget {
final VoidCallback onNavigate;
const FirstScreen({
Key? key,
required this.onNavigate,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Fisrt screen'),
),
body: Center(
child: ElevatedButton(
onPressed: onNavigate,
child: const Text('Replace'),
),
),
);
}
}
class SecodScreen extends StatelessWidget {
const SecodScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second screen'),
),
);
}
}
What I want to achieve:
Screen 1 is the initial screen, and goes to Screen 2 (via restorablePush)
Screen 2 is a restorable page, and goes to Screen 3 (via restorablePush)
Screen 3 is a restorable page, and goes back to Screen 1 (via pushAndRemoveUntil)
The restoring stuff works fine, but when I go back to Screen 1 from Screen 3 then kill the app and reopen it, I get this failed assertion error:
_history.isNotEmpty:
All routes returned by onGenerateInitialRoutes are not restorable.
Please make sure that all routes returned by onGenerateInitialRoutes
have their RouteSettings defined with names that are defined in the
app's routes table.
I've look at onGeneralInitialRoutes but I can't figure out how to solve this. I also tried doing everything with named routes, but it didn't change anything.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Screen1(),
restorationScopeId: 'root',
);
}
}
class Screen1 extends StatefulWidget {
const Screen1({Key? key}) : super(key: key);
#override
State<Screen1> createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
static Route<void> _myRouteBuilder(BuildContext context, Object? arguments) {
return MaterialPageRoute<void>(
builder: (BuildContext context) => const Screen2(),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
onPressed: () {
Navigator.restorablePush(context, _myRouteBuilder);
},
child: const Text('Go to Screen 2')),
),
);
}
}
class Screen2 extends StatefulWidget {
const Screen2({Key? key}) : super(key: key);
#override
State<Screen2> createState() => _Screen2State();
}
class _Screen2State extends State<Screen2> {
static Route<void> _myRouteBuilder(BuildContext context, Object? arguments) {
return MaterialPageRoute<void>(
builder: (BuildContext context) => const Screen3(),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Screen 2')),
body: Center(
child: TextButton(
onPressed: () => Navigator.restorablePush(context, _myRouteBuilder),
child: const Text('Go to Screen 3'),
)));
}
}
class Screen3 extends StatelessWidget {
const Screen3({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Screen 3')),
body: Center(
child: TextButton(
onPressed: () => Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const Screen1()),
((route) => false)),
child: const Text('Go back to Screen 1'),
),
));
}
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SharedPrefs.init();
runApp(MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => UserProvider()),
Provider(
create: (context) => AuthService(),
),
],
child: Builder(builder: (context) {
return const MyApp();
})));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
context.read<AuthService>().getUserData(context);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Amazon Clone',
onGenerateRoute: (settings) => generateRoute(settings),
theme: ThemeData(
scaffoldBackgroundColor: GlobalVariables.backgroundColor,
colorScheme:
const ColorScheme.light(primary: GlobalVariables.secondaryColor),
appBarTheme: const AppBarTheme(
elevation: 0,
iconTheme: IconThemeData(color: Colors.black),
),
),
home: Builder(builder: (context) {
return context.watch<UserProvider>().user.token.isNotEmpty
? const HomeScreen()
: const AuthScreen();
}));
}
}
i am using snackbar from utils file i get no scaffoldmessenger widget found error.I tried to use builder scaffoldmessengerkey but didnt work.what can i do.i used try catch with snackbar.What is the solve of my problem
You need both MaterialApp and a Scaffold widget in the tree before using ScaffoldMessenger. For example:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp( // required MaterialApp
title: _title,
home: Scaffold( // required Scaffold
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatelessWidget(),
),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return OutlinedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('A SnackBar has been shown.'),
),
);
},
child: const Text('Show SnackBar'),
);
}
}
I am trying to move from one page to another via Navigator.push. Here is my code:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int count = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepOrange,
title: const Text("Noice!"),
),
body: ElevatedButton(
child: const Text('About'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AboutScreen(),
),
);
},
),
class AboutScreen extends StatelessWidget {
const AboutScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 0, 255, 8),
title: const Text("Flutter ballert")),
);
}
}
The code compiles and I can access the app, but clicking the button leads to an error:
Exception has occurred.
FlutterError (Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.)
I know that in the offical docs the example for navigation is a tiny bit different. They dont return MaterialApp, instead they return Scaffold. Whats the difference between the two? Why should I return MaterialApp in the first place? And why doesnt it work with returning MaterialApp?
I dont know why this happens. I am new to flutter, so apologies if thats really trivial.
EDIT: Duplicate of:
Navigator operation requested with a context that does not include a Navigator
The problem is with the context. To fix this. Wrap your widget in a Builder() Class:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int count = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(builder: (context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepOrange,
title: const Text("Noice!"),
),
body: ElevatedButton(
child: const Text('About'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AboutScreen(),
));
},
),
);
}),
);
}
}
class AboutScreen extends StatelessWidget {
const AboutScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 0, 255, 8),
title: const Text("Flutter ballert")),
);
}
}
Here is a YouTube video by the Google team explaining Builder
You need to pass the context:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int count = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepOrange,
title: const Text("Noice!"),
),
body: ElevatedButton(
child: const Text('About'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => AboutScreen(),
),
);
},
),
),
);
}
}
class AboutScreen extends StatelessWidget {
const AboutScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 0, 255, 8),
title: const Text("Flutter ballert")),
);
}
}
Basically you did:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AboutScreen(),
),
);
But you need to do this:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => AboutScreen(),
),
);
I would like to keep showing a floating button or widget in Flutter even though the page is changed by Navigator.of(context).push() like mini music player which placed in the bottom.
How can I implement that ??
You can extract the scaffold as a layout that contains a bottom sheet, and use this layout in every page you build, passing in the title, body, etc., so that the bottom sheet is persistent in all pages. Snippet below.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Persistent Bottom Sheet',
theme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.dark,
),
initialRoute: "/",
routes: {
"/": (context) => Home(),
"/library": (context) => Library(),
},
);
}
}
class Home extends StatelessWidget {
Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Layout(
title: "Home",
body: Center(
child: Text("Home"),
),
actions: <Widget>[
InkWell(
onTap: () {
Navigator.of(context).pushNamed("/library");
},
child: Tooltip(
message: "Go To Library",
child: Padding(
padding: const EdgeInsets.all(12),
child: Icon(Icons.library_music),
),
),
)
],
);
}
}
class Library extends StatelessWidget {
Library({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Layout(
title: "Library",
body: Center(
child: Text("Library"),
),
);
}
}
class Layout extends StatelessWidget {
final String title;
final Widget body;
final List<Widget>? actions;
const Layout({
Key? key,
required this.title,
required this.body,
this.actions,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(title),
actions: actions,
),
body: body,
bottomSheet: Container(
width: double.infinity,
padding: const EdgeInsets.all(15),
color: Theme.of(context).cardColor,
child: Text("Persistent Bottom Sheet"),
),
);
}
}