I'm receiving this error when running my flutter web, unexpected null value and when I look at my terminal it directs me to my main.dart where I'm being told that the error is coming from my Material widget.
Whereas I'm not understanding what's causing the error.
The following TypeErrorImpl was thrown building Builder:
Unexpected null value.
The relevant error-causing widget was:
Material Material
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:bwamnewsappadmin/pages/home.dart';
import 'package:bwamnewsappadmin/pages/sign_in.dart';
import 'package:provider/provider.dart';
import 'blocs/admin_bloc.dart';
import 'blocs/notification_bloc.dart';
import 'blocs/comment_bloc.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(providers: [
ChangeNotifierProvider<AdminBloc>(create: (context) => AdminBloc()),
ChangeNotifierProvider<CommentBloc>(create: (context) => CommentBloc()),
ChangeNotifierProvider<NotificationBloc>(create: (context) => NotificationBloc())
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
scrollBehavior: TouchAndMouseScrollBehavior(),
theme: ThemeData(
scaffoldBackgroundColor: Colors.white,
textTheme: GoogleFonts.poppinsTextTheme(),
appBarTheme: AppBarTheme(
color: Colors.white,
titleTextStyle: GoogleFonts.poppins(
color: Colors.grey[900],fontWeight: FontWeight.w600, fontSize: 18
),
elevation: 0,
actionsIconTheme: IconThemeData(
color: Colors.grey[900],
),
iconTheme: IconThemeData(
color: Colors.grey[900]
)
),
),
home: MyApp1(),
),
);
}
}
class MyApp1 extends StatelessWidget {
const MyApp1({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final ab = context.watch<AdminBloc>();
return ab.isSignedIn == false ? SignInPage() : HomePage();
}
}
class TouchAndMouseScrollBehavior extends MaterialScrollBehavior {
// Override behavior methods and getters like dragDevices
#override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
// etc.
};
}
I am looking for some help with my code. I want to create some swappable cards and for that I have created blocs. However, when I finished and tried to launch it, following message appears :
Bad state: add(LoadMissionsEvent) was called without a registered event handler.
Make sure to register a handler via on((event, emit) {...})
class MyApp extends StatelessWidget {
const MyApp({
Key key,
}) : super(key: key);
// final StreamChatClient client;
// final Channel channel;
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (_) => SwipeBloc()
..add(LoadMissionsEvent(
missionDescriptions:
MissionDescription.missionsDescriptions)))
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: "Student App",
home: MissionChoice(),
localizationsDelegates: [GlobalMaterialLocalizations.delegate],
supportedLocales: [Locale('en'), Locale('fr')],
// Scaffold(
// backgroundColor: d_green,
// ),
));
}
}
I made a changeable theme in flutter and later I made multi-language support, I used getx for theme switching, I used easy_localization for language change. When I use GetMeterialapp on the main page, it doesn't work, when I do Meterialapp it works multi-language, but the theme change does not work. import 'package:get/get.dart' on another page; i am using and when i use easy_localization here easy_localization is not working. I'm canceling getx is working. I couldn't get out of this situation. If I can't solve it, I will either give up without changing the theme or multi-language support.
await EasyLocalization.ensureInitialized();
runApp(EasyLocalization(supportedLocales: [
Locale("en", "US"),
Locale("tr", "TR"),
], path: "assets/Language", saveLocale: true, child: MyApp()));
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Home Page',
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
theme: Themes.light,
darkTheme: Themes.dark,
themeMode: ThemeService().theme,
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
Initialize GetStorage inside main method.
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await GetStorage.init();
runApp(MyApp());
}
Create storage object.
final storage = GetStorage();
Set a default value if storage is null.
storage.writeIfNull('darkmode', false);
Read the theme mode value.
bool isDarkMode = storage.read('darkmode');
Apply the theme mode.
Switch(
value: isDarkMode ,
onChanged: (value) => storage.write('darkmode', value),
)
Full code:
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import 'package:get/get.dart';
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await GetStorage.init();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final storage = GetStorage();
#override
Widget build(BuildContext context) {
appdata.writeIfNull('darkmode', false);
return SimpleBuilder(
builder: (_)
{
bool isDarkMode = storage.read('darkmode');
return GetMaterialApp(
theme: isDarkMode ? ThemeData.dark() : ThemeData.light(),
home: Scaffold(
appBar: AppBar(title: Text("Getx Dynamic theme change"),),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(isDarkMode ? 'images/night.png' :'images/day.png' ,width: 100,height: 100,),
Switch(
value: isDarkMode ,
onChanged: (value) => storage.write('darkmode', value),
)
],
),
),
),
);
},
);
}
}
I'm getting a peculiar bug when using a ListWheelScrollView to display image widgets on iOS. It is contained in one page of a PageView, and it works fine until I minimize the app. If the app is resumed after entering the background and then I switch to the page that contains the scrollview (either by switching away and switching back after resuming or by switching away before minimizing and then switching back after resuming), the visible images fail to display and the output reads as follows:
════════ Exception caught by image resource service
════════════════════════════ The method 'toDouble' was called on null.
Receiver: null Tried calling: toDouble()
════════════════════════════════════════════════════════════════════════════════
Below is a simple example that demonstrates the problem:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ListWheel Issue',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'ListWheelScrollview Bug'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _currentIndex = 0;
PageController _pageController;
List<Widget> get _tabs => [
ScrollScreen(),
Container(),
Container(),
];
#override
void initState() {
_pageController = PageController();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: PageView(
controller: _pageController,
children: _tabs,
)),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.refresh), title: Text('tab1')),
BottomNavigationBarItem(icon: Icon(Icons.movie), title: Text('tab2')),
BottomNavigationBarItem(
icon: Icon(Icons.search), title: Text('tab3')),
],
currentIndex: _currentIndex,
onTap: (i) {
setState(() {
_currentIndex = i;
_pageController.animateToPage(i,
curve: Curves.easeOut, duration: Duration(milliseconds: 200));
});
},
),
);
}
}
class ScrollScreen extends StatefulWidget {
#override
_ScrollScreenState createState() => _ScrollScreenState();
}
class _ScrollScreenState extends State<ScrollScreen> {
var _exImage = AssetImage('assets/images/no_image.png');
#override
Widget build(BuildContext context) {
List<AssetImage> _images = [
_exImage,
_exImage,
_exImage,
];
return Center(
child: ListWheelScrollView.useDelegate(
itemExtent: 300,
childDelegate: ListWheelChildLoopingListDelegate(
children: _images
.map((e) => Center(
child: Image(
image: e,
)))
.toList())),
);
}
}
Any help with this would be greatly appreciated.
I found out a solution.
#override
void didChangeDependencies() {
super.didChangeDependencies();
precacheImage(AssetImage('assets/icons/settings_icon.png'), context);
}
after precaching the images used in the ListWheelScrollView, the error no longer appears
Idk if flutter team will fix it in the future or not.
I figured out a bit more about the issue. It turns out null values were being passed as "minScrollExtent" and "maxScrollExtent" into the _getItemFromOffset function in the list_wheel_scroll_view.dart file, which were, in turn being passed into the _clipOffsetToScrollableRange function.
As a workaround, I ended up changing the return value of the _clipOffsetScrollableRange to the following:
return (_clipOffsetToScrollableRange(
offset,
minScrollExtent ?? -double.infinity,
maxScrollExtent ?? double.infinity) /
itemExtent)
.round();
This likely does not address the underlying issue, but has resulted in my app working properly.
I have many screens, and I'm using the Navigator. I'd like to use "named routes", but I also need to pass non-string (such as images) to my next route.
I can't use pushNamed() because I can't pass non-string data to it.
How can I use a named route + send non-string data?
EDIT:
It is now possible to pass complex arguments to Navigator.pushNamed:
String id;
Navigator.pushNamed(context, '/users', arguments: id);
It can then be used within onGenerateRoute to customize route building with these arguments:
MaterialApp(
title: 'Flutter Hooks Gallery',
onGenerateRoute: (settings) {
final arguments = settings.arguments;
switch (settings.name) {
case '/users':
if (arguments is String) {
// the details page for one specific user
return UserDetails(arguments);
}
else {
// a route showing the list of all users
return UserList();
}
default:
return null;
}
},
);
You can use the parameter routes of your App for directly passing arguments.
Like this:
routes: {
HomePage.route: (_) => HomePage(),
DetailsPage.route: (context) =>
DetailsPage(ModalRoute.of(context).settings.arguments),
},
In this case, the complete example will look like the next:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
initialRoute: HomePage.route,
routes: {
HomePage.route: (_) => HomePage(),
DetailsPage.route: (context) =>
DetailsPage(ModalRoute.of(context).settings.arguments),
},
);
}
}
class HomePage extends StatelessWidget {
static const String route = '/';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, '/details',
arguments: ScreenArguments(
'My Details',
'Some Message',
));
},
),
);
}
}
class DetailsPage extends StatelessWidget {
static const String route = '/details';
final ScreenArguments arguments;
DetailsPage(this.arguments);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(arguments.title),
),
body: Center(
child: Text(arguments.message),
),
);
}
}
class ScreenArguments {
final String title;
final String message;
ScreenArguments(this.title, this.message);
}
By Using Maps
While pushing the arguments u can push that in map form and can do the same while extracting them.
e.g.
While Pushing
Navigator.of(context).pushNamed(
'second',
arguments: {
'title':'This is a String',
or
'Fx': This could be any widget or Function
}
While Extracting the arguments in the target page
final routes=ModalRoute.of(context).settings.arguments as Map<String,String>;
return Scaffold(
appBar: AppBar(
title: Text(routes['title']),
),
body: Container(
child: Center(
child: RaisedButton(
child: Text("Back"),
onPressed: ()=>Navigator.of(context).pop(),
),
),
),
);
and choose your map accordingly accordingly
UPDATE: 3rd April, 2021
This answer is old and Flutter navigation has evolved considerably since then. This may not be the best way to handle navigation with current versions, please consider other answers. I will leave this here for historical purposes.
Using onGenerateRoute it is easy to pass complex arguments on route transition with Navigator.pushNamed or Navigator.pushReplacementNamed
A minimal setup to show the concept would be
main.dart
import 'package:flutter/material.dart';
import 'package:navigator/routes.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Navigation Demo',
theme: ThemeData(
primarySwatch: Colors.teal,
),
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute(
builder: (BuildContext context) => makeRoute(
context: context,
routeName: settings.name,
arguments: settings.arguments,
),
maintainState: true,
fullscreenDialog: false,
);
},
);
}
}
routes.dart
In the _buildRoute method we check the route name and cast arguments to a required type.
A draw back is that the type has to be defined before hand if required argument is not a simple type.
import 'package:flutter/material.dart';
import 'package:navigator/list.dart';
import 'package:navigator/details.dart';
Widget makeRoute(
{#required BuildContext context,
#required String routeName,
Object arguments}) {
final Widget child =
_buildRoute(context: context, routeName: routeName, arguments: arguments);
return child;
}
Widget _buildRoute({
#required BuildContext context,
#required String routeName,
Object arguments,
}) {
switch (routeName) {
case '/':
return ArticleList();
case '/ArticleView':
Article article = arguments as Article;
return ArticleView(article: article);
default:
throw 'Route $routeName is not defined';
}
}
Views
list.dart
Construct the route argument using a defined type, Article in our case.
import 'package:flutter/material.dart';
import 'package:navigator/details.dart' show Article;
class ArticleList extends StatefulWidget {
#override
_ArticleListState createState() => _ArticleListState();
}
class _ArticleListState extends State<ArticleList> {
List<Article> articles = [
Article(
id: 1,
title: 'Article 1',
author_name: 'Nilotpal',
summary: 'Article 1 summary'),
Article(
id: 2,
title: 'Article 2',
author_name: 'Mike',
summary: 'Article 2 summary'),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Articles'),
),
body: Center(
child: Column(
children: <Widget>[
ListTile(
title: Text('${articles[0].title}'),
subtitle: Text('by ${articles[0].author_name}'),
onTap: () {
Navigator.of(context)
.pushNamed('/ArticleView', arguments: articles[0]);
},
),
ListTile(
title: Text('${articles[1].title}'),
subtitle: Text('by ${articles[1].author_name}'),
onTap: () {
Navigator.of(context)
.pushNamed('/ArticleView', arguments: articles[1]);
},
),
],
),
),
);
}
}
details.dart
Define a type for the arguments
import 'package:flutter/material.dart';
class Article {
final int id;
final String author_name;
final String title;
final String summary;
Article(
{#required this.id,
#required this.author_name,
#required this.title,
#required this.summary});
}
class ArticleView extends StatelessWidget {
final Article _article;
ArticleView({#required Article article}) : _article = article;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('${_article.title}'),
),
body: SafeArea(
top: true,
child: Center(
child: Column(
children: <Widget>[
Text('${_article.author_name}'),
Text('${_article.summary}'),
],
),
),
),
);
}
}
The Flutter Cookbook shows how to navigate to a new page and pass non-string data to it.
Passing data to next page
I started with Navigator.pushedNamed() because it was simple and I didn't have any data to pass. When my needs changed and I wanted to pass data, I switched to Navigator.push().
Example:
var nextPageData = {foo:'bar'};
Navigator.push(
context,
MaterialPageRoute(builder: (context) =>
MyNextPage(myData: nextPageData))
);
I am capturing images with camera then passing them through to a confirmation page like so:
ImagePicker.pickImage(source: source).then((File file) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MediaCaptured(file: file),
));
});
You could easily do the same with any type of file or non-string data.
var foo = "non-string data";
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MediaCaptured(foo: foo),
));
Call the next page in the route by it's class name, as above.
Just make sure your new page accepts this in it's constructor.
// Stateful Widget
class MediaCaptured extends StatefulWidget {
MediaCaptured({ Key key, #required this.foo,}) : super(key: key);
final var foo;
}
// StatelessWidget
class MediaCaptured extends StatelessWidget {
MediaCaptured(this.foo);
var foo;
}
For the outcome of this problem, I developed the package
link: https://pub.dartlang.org/packages/navigate
That provide to much your expect and easy to use
Navigate.navigate(context,
"home",
transactionType:TransactionType.fromLeft , // optional
replaceRoute: ReplaceRoute.thisOne, //optional
arg: {"transactionType":TransactionType.fromLeft,"replaceRoute":ReplaceRoute.thisOne} //optional
);
From First StateFul class :
Navigator.of(context).pushNamed('/pending_order',arguments: {"staff" : staffObj});
To Second StateFul class :
class PendingOrders extends StatefulWidget {
#override
_PendingOrdersState createState() => _PendingOrdersState();
}
class _PendingOrdersState extends State<PendingOrders> {
StaffModel staffModelObj;
#override
Widget build(BuildContext context) {
final routes =
ModalRoute.of(context).settings.arguments as Map<String, dynamic>;
if (routes != null) {
staffModelObj = routes["staff"];
}
return Scaffold(...);}}
I wanted to use a named route navigator that has values as below
Navigator.pushNamed(context, '/increaseBalanceAccountPage',
arguments: {'accountBalanceViewModel': result},);
so I should define that route in materialApp widget in the start of app but I should give parameters in the instance so I solve my problem with some modification of #YuriyLuchaninov code Like below:
MaterialApp(
initialRoute: "/",
routes: {
'/': (context) => SplashScreenPage(),
"/increaseBalanceAccountPage":
(context) =>
UserAccountBalancePage(accountBalanceViewModel: Map<String,Object>
.from(ModalRoute.of(context)!.settings.arguments as Map).values.first as
AccountBalanceViewModel)
},
.....
Consider this trivial example from flutter. You have a class created as follows
class ScreenArguments {
final String title;
final String message;
ScreenArguments(this.title, this.message);
}
Now we will pass an object of this class as an argument as follows
Navigator.pushNamed(
context,
ExtractArgumentsScreen.routeName,
arguments: ScreenArguments(
'Extract Arguments Screen',
'This message is extracted in the build method.',
),
);
And then you can extract the arguments as follows
final args = ModalRoute.of(context)!.settings.arguments as ScreenArguments;
And that is all. Hope this helps Source: passing arguments to a named route
We can pass any type of arguments when declaring routes as constructor arguments as below,
For example to send a list of Strings,
List<String> titles = [];
void main() => runApp(
new MaterialApp(
home: new FirstPage(),
routes: <String, WidgetBuilder>{
"/SecondPage": (BuildContext context) => new SecondPage(titles),
},
),
);
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Container(
child: new RaisedButton(onPressed: () {
Navigator.of(context).pushNamed('/SecondPage');
}),
);
}
}
class SecondPage extends StatelessWidget {
final List<String> titles;
SecondPage(this.titles);
#override
Widget build(BuildContext context) {
return new ListView.builder(
itemBuilder: (context, index) {
return new ListTile(
title: new Text(titles[index]),
);
},
);
}
}