I'm new to flutter, In MaterailApp Widget have an attribute called onUnknownRoute. What is the main use of onUnknownRoute?
Thanks for your help!
You can copy paste run full code below
In flutter web, when user manually key a undefine route, it can produce like 404 effect
full code
import 'package:flutter/material.dart';
void main() {
runApp( MaterialApp(
initialRoute: "/screen1",
routes: <String, WidgetBuilder>{
'/screen1': (BuildContext context) => Screen1(),
'/screen2': (BuildContext context) => Screen2(),
'/screen3': (BuildContext context) => Screen3(),
'/screen4': (BuildContext context) => Screen4()
},
onUnknownRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
builder: (BuildContext context) =>
Scaffold(body: Center(child: Text('Not Found'))),
);
},
)
);
}
class Screen1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
class Screen3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
class Screen4 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
onUnknownRoute property is used to handle the worst case when the app navigation fails to get a route. If not handled, exception will be generated.
The navigator widget manages a stack of Route objects.
Route objects are nothing but full-screen elements like "screens" or "pages".
The navigator manages navigation between the screens in any app.
The Navigator for any app is only built if routes are provided by one of below items
home
routes
onGenerateRoute
onUnknownRoute
If the app only has one page, then you can specify it using home.
Else all routes will be in routes table including the home
If a route is requested that is not specified in routes table (or by home), then the onGenerateRoute callback is called
when even onGenerateRoute fails to generate a route, the property OnUnknownRoute will be triggered to handle the scenario.
We can handle an unknown route as below,
return MaterialApp(
title: 'Named Routing',
onGenerateRoute: router.generateRoute,
onUnknownRoute: (settings) => MaterialPageRoute(
builder: (context) => UndefinedView(
name: settings.name,
)),
initialRoute: HomeViewRoute,
);
If unknown route event is not handled using the onUnknownRoute property, flutter may throw an exception
The solution is coding in routes -> Example
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Material App',
// home: HomePage(),
initialRoute: '/',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => HomePage(),
'alert': (BuildContext context) => AlertPage(),
'avatar': (BuildContext context) => AvatarPage(),
},
***onUnknownRoute: (settings) {},***
onGenerateRoute: (settings) {
return MaterialPageRoute(
builder: (BuildContext context) => AlertPage());
},
);
}
}
Related
im new on flutter, and i experience some troubles after i add a new provider into my main.
this is my main code:
import 'package:catalo_gate/providers/providers.dart';
import 'package:catalo_gate/services/auth_service.dart';
import 'package:catalo_gate/services/products_service.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'screens/screens.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const AppState());
}
class AppState extends StatelessWidget {
const AppState({super.key});
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => ProductsService()),
ChangeNotifierProvider(
create: (_) => LoginProvider(authService: AuthService())),
],
child: const MyApp(),
);
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'CataloGate',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
initialRoute: 'login',
routes: {
'login': (BuildContext context) => const LoginScreen(),
'register': (BuildContext context) => const RegisterScreen(),
'checking': (BuildContext context) => const CheckAuthScreen(),
'home': (BuildContext context) => const HomeScreen(),
'product': (BuildContext context) => const ProductScreen(),
'productsList': (BuildContext context) => const ProductsListScreen(),
//SubScreens
'listaReposicion': (BuildContext context) =>
const ListaDiasReposicionScreen(),
'entregas': (BuildContext context) => const DiasDeEntregaScreen(),
'unidadesPorBulto': (BuildContext context) =>
const UnidadesPorBultoScreen(),
},
);
}
}
everytime i try to make login i receive this message:
ProviderNotFoundException (Error: Could not find the correct Provider above this HomeScreen Widget
This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your main.dart and performed a hot-reload.
To fix, perform a hot-restart.
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that HomeScreen is under your MultiProvider/Provider.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>().toString()),
);
}
consider using builder like so:
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context, child) {
// No longer throws
return Text(context.watch<Example>().toString());
}
);
}
If none of these solutions work, consider asking for help on StackOverflow:
https://stackoverflow.com/questions/tagged/flutter
)
Can someone Help me??
i'd try a lot of options, changing the way to use the ChangeNotifierProvider for example
I'm trying to use Bloc provider for user authentication in my flutter app. When I try to access the data i'm always getting this error even though I double checked all the files.
This is the error i'm getting:
Error: Could not find the correct Provider<StateStreamable<Object?>> above this
BlocListener<StateStreamable<Object?>, Object?> Widget
This happens because you used a `BuildContext` that does not include the provider
main.dart:
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => AuthBloc(LoginInitState(), AuthRepository()))
],
child: MaterialApp(
title: 'Flutter app',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity),
home: const LoginPage(),
),
);
}
}
parts from login.dart:
#override
void initState() {
authBloc = BlocProvider.of<AuthBloc>(context);
super.initState();
}
######################################################
return Scaffold(
backgroundColor: Colors.grey[300],
body: BlocListener(
listener: (context, state) {
if (state is UserLoginSuccessState) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const HomeScreen()));
}
},
child: SafeArea...
I'm still new to flutter and struggling with the state management part, I'd be glad if anybody can help!
In your BlocListener you're missing the State and the Bloc
Here's what I mean
BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
if (state is UserLoginSuccessState) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const HomeScreen()));
}
},
child: SafeArea...
if we use MaterialApp, we build like this:
Navigator(
key: naviKey,
onGenerateRoute: (routeSettings) => MaterialPageRoute(
builder: (context)=>Container(),
),
)
and now, how to build if we use Getx?
Routing in GetX can be setup like so. Note Page1.id is after putting static const id = 'page_1 in Page1 so you don't have to use raw strings.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
home: Page1(),
routes: {
Page1.id: (context) => Page1(),
Page2.id: (context) => Page2(),
},
);
}
}
or like this
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
home: Page1(),
getPages: [
GetPage(name: Page1.id, page: () => Page1()),
GetPage(name: Page1.id, page: () => Page1()),
],
);
}
}
You can setup the list of routes on another page if you don't want to clutter up your GetMaterialApp with all your routes.
Then when you want to navigate you can do it like this
Get.to(Page2());
I apply the same bloc pattern in the login and signup form,when i have only one provider, is not a problem. But now i implement second provider. This provider controller a page view, the index and other parameters. The problem is that i implement multiprovider, when i start login page i have an error.This is my code.
class MyApp extends StatelessWidget {
//final _prefs = new PreferenciasUsuario();
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => new UiProvider()),
Provider(create: (_) => new BlocFormProvider())
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demos',
initialRoute: 'init',
routes: {
'init': (BuildContext context) => InitialPage(),
'login': (BuildContext context) => LoginPage(),
'signup': (BuildContext context) => SignUpPage(),
'home': (BuildContext context) => HomePage(),
'remember': (BuildContext context) => RememberPasswordPage(),
'start': (BuildContext context) => StartPage()
}),
);
}
}
and this is my bloc provider
import 'package:flutter/material.dart';
import 'login_bloc.dart';
class BlocFormProvider extends InheritedWidget {
static BlocFormProvider _instancia;
factory BlocFormProvider({Key key, Widget child}) {
if (_instancia == null) {
_instancia = new BlocFormProvider._internal(key: key, child: child);
}
return _instancia;
}
final loginBloc = LoginBloc();
BlocFormProvider._internal({Key key, Widget child})
: super(key: key, child: child);
#override
bool updateShouldNotify(covariant InheritedWidget oldWidget) => true;
static LoginBloc of(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<BlocFormProvider>()
.loginBloc;
}
}
Finally this is the error:
The getter 'loginBloc' was called on null.
Receiver: null
Tried calling: loginBloc
The relevant error-causing widget was LoginPage
Thanks for your help.
I have code as below, it's no problems.
void main() async {
Widget _defaultHome = new LoginPage();
runApp(new MaterialApp(
title: 'App',
debugShowCheckedModeBanner: false,
home: _defaultHome,
routes: <String, WidgetBuilder>{
// Set routes for using the Navigator.
'/tabs': (BuildContext context) => new TabsPage(),
'/login': (BuildContext context) => new LoginPage()
},
));
}
I want to change it to code as below, how can I pass _defaultHome to class MyApp?
void main() async {
Widget _defaultHome = new LoginPage();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
// final textTheme = Theme.of(context).textTheme;
return MaterialApp(
title: 'Gaia',
debugShowCheckedModeBanner: false,
home: _defaultHome,
routes: <String, WidgetBuilder>{
// Set routes for using the Navigator.
'/tabs': (BuildContext context) => new TabsPage(),
'/login': (BuildContext context) => new LoginPage()
},
);
}
}
Use the below code and any parameter can pass through constructor.
void main() async {
Widget _defaultHome = new LoginPage();
runApp(MyApp(defaultHome: _defaultHome,));
}
class MyApp extends StatelessWidget {
final Widget defaultHome;
const MyApp({
#required this.defaultHome,
Key key,
}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
// final textTheme = Theme.of(context).textTheme;
return MaterialApp(
title: 'Gaia',
debugShowCheckedModeBanner: false,
home: defaultHome,
routes: <String, WidgetBuilder>{
// Set routes for using the Navigator.
'/tabs': (BuildContext context) => new TabsPage(),
'/login': (BuildContext context) => new LoginPage()
},
);
}
}
You can either decide to pass it via Provider or via parameters.
This is the way you pass it via parameters with optional parameters:
void main() async {
final Widget _defaultHome = new LoginPage();
runApp(MyApp(homePage: _defaultHome));
}
class MyApp extends StatelessWidget {
MyApp({this.homePage});
final Widget homePage;
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
// final textTheme = Theme.of(context).textTheme;
return MaterialApp(
title: 'Gaia',
debugShowCheckedModeBanner: false,
home: _defaultHome,
routes: <String, WidgetBuilder>{
// Set routes for using the Navigator.
'/tabs': (BuildContext context) => new TabsPage(),
'/login': (BuildContext context) => homePage
},
);
}
}
You can pass it by a parameters in your constructor and assign it to your home.
class MyApp extends StatelessWidget {
// This widget is the root of your application.
final Widget defaultHome;
const MyApp({Key key, #required this.defaultHome}) : super(key: key);
#override
Widget build(BuildContext context) {
// final textTheme = Theme.of(context).textTheme;
return MaterialApp(
title: 'Gaia',
debugShowCheckedModeBanner: false,
home: defaultHome,
routes: <String, WidgetBuilder>{
// Set routes for using the Navigator.
'/tabs': (BuildContext context) => new TabsPage(),
'/login': (BuildContext context) => new LoginPage()
},
);
}
}