Missing concrete implementation of 'State.build' - flutter

I am in the learning stage of flutter and facing errors. I am watching a course on Udemy. I am trying to build a Personal Expense Tracker. It's a fundamental project but, as I already told I am currently learning and am facing an error. Any help would be appreciated.
This is the code of my main.dart file:
import 'package:flutter/material.dart';
import './widgets/transaction_list.dart';
import './widgets/new_transactions.dart';
import './widgets/chart.dart';
import './models/transaction.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final ThemeData theme = ThemeData(
primarySwatch: Colors.primaries[1],
errorColor: Colors.red,
fontFamily: 'Quicksand',
);
return MaterialApp(
title: 'Expense Planner',
theme: theme.copyWith(
colorScheme: theme.colorScheme.copyWith(secondary: Colors.amber),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<Transaction> _userTransactions = [];
List<Transaction> get _recentTransactions {
return _userTransactions.where((tx) {
return tx.date.isAfter(
DateTime.now().subtract(
Duration(days: 7),
),
);
}).toList();
}
void _addNewTransaction(
String txTitle, double txAmount, DateTime chosenDate) {
final newTx = Transaction(
title: txTitle,
amount: txAmount,
date: chosenDate,
id: DateTime.now().toString(),
);
setState(() {
_userTransactions.add(newTx);
});
}
void _startAddNewTransaction(BuildContext ctx) {
showModalBottomSheet(
context: ctx,
builder: (_) {
return GestureDetector(
onTap: () {},
child: NewTransaction(_addNewTransaction),
behavior: HitTestBehavior.opaque,
);
},
);
}
void _deleteTransaction(String id) {
setState(() {
_userTransactions.removeWhere((tx) => tx.id == id);
{
;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Expense Planner',
style: TextStyle(
fontFamily: 'OpenSans',
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
],
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Chart(_recentTransactions),
TransactionList(_userTransactions, _deleteTransaction),
],
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
);
}
});
}
}
There's some error in the _MyHomePageState class. it shows the following error
Missing concrete implementation of 'State.build'.
Try implementing the missing method, or make the class abstract.
However when I try to make the _MyHomePageState class abstract it shows the following:
Abstract classes can't be instantiated.
Try creating an instance of a concrete subtype.
Thanks & Regards,
Harshit Chitkara

I think 'home: MyHomePage(),' is waiting for a Widget. You have to build a Widget arround the List. After that you probably need a Scaffold inside the Widget.
#override
Widget build(BuildContext context) {
return Scaffold(
child: List<Transaction> get _recentTransactions {
return _userTransactions.where((tx) {
return tx.date.isAfter(
DateTime.now().subtract(
Duration(days: 7),
),
);
}).toList();
}
);
}
This should fix the current problem, but you can't have a return inside a return.

Related

Implementation of basic flutter search bar failed

So I followed a tutorial on how to implement a basic Flutter search bar with search Delegation. You can find the tutorial on this link: https://www.youtube.com/watch?v=FPcl1tu0gDs
class DataSearch extends SearchDelegate<String>{
final wordssuggest=["Word1","Word2"];
final recentwords=["Word1"];
#override
List<Widget> buildActions(BuildContext context){
return [
IconButton(onPressed: (){
query=" ";
}, icon: Icon(Icons.clear))
];
//actions for appbar
}
#override
Widget buildLeading(BuildContext context){
return IconButton(onPressed: (){
close(context, null);
}, icon: Icon(Icons.search));
//leasding icon on the left of the app bar
}
#override
Widget buildResults(BuildContext context){
//show some result
return Container(
color: Colors.grey,
height: 200,
width: 200,
child: Center(child: Text(query),)
);
}
#override
Widget buildSuggestions(BuildContext context){
//show suggestions
final suggestionList =query.isEmpty?
recentwords:wordssuggest.where((p)=>p.startsWith(query)).toList();
return ListView.builder(itemBuilder: (context, index)=>ListTile(
onTap:(){
showResults(context);
} ,
leading: Icon(Icons.work_rounded),
title: RichText(text: TextSpan(text: suggestionList[index].substring(0, query.length),
style: TextStyle(color:Colors.blue, fontWeight: FontWeight.bold),
children: [TextSpan(
text:suggestionList[index].substring(query.length),
style:TextStyle(color:Colors.grey)
)]),
)
),
itemCount: suggestionList.length,);
}
}
However, what is not working for me:
For SearchDelegate method in the DataSearch class:
'Methods must have an explicit list of parameters.Try adding a parameter list.dart(missing_method_parameters)'
For buildActions, buildLeading, builduggestions and buildResults Widgets:
'The declaration 'buildActions' isn't referenced.'
Inside buildSuggestions:
The method 'showResults' isn't defined for the type '_MainPageState'.
Inside buildLeading:
The method 'close' isn't defined for the type '_MainPageState'.
Please help
Maybe your problem is occur because of calling the search delegate class.
this code solve your problem!
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Secondpage(title: 'Flutter Demo Home Page'),
);
}
}
class Secondpage extends StatelessWidget {
final String title;
Secondpage({required this.title});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
actions: [
IconButton(icon: Icon(Icons.add), onPressed: () async {
await showSearch<String>(
context: context,
delegate: DataSearch(),
);
},
)
],
));
}
}
Search Delegate
class DataSearch extends SearchDelegate<String>{
final wordSuggest=["Word1","Word2","Word3","Word4", "Word5","Word6", ];
final recentWords=["Word1"];
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = "";
// showSuggestions(context);
},
),
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
onPressed: () {
close(context, 'null');
},
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
);
}
#override
Widget buildResults(BuildContext context){
//show some result
return Container(
color: Colors.grey,
height: 200,
width: 200,
child: Center(child: Text(query),)
);
}
#override
Widget buildSuggestions(BuildContext context){
//show suggestions
final suggestionList =query.isEmpty?
recentWords:wordSuggest.where((p)=>p.startsWith(query)).toList();
return ListView.builder(itemBuilder: (context, index)=>ListTile(
onTap:(){
showResults(context);
} ,
leading: Icon(Icons.work_rounded),
title: RichText(text: TextSpan(text: suggestionList[index].substring(0, query.length),
style: TextStyle(color:Colors.blue, fontWeight: FontWeight.bold),
children: [TextSpan(
text:suggestionList[index].substring(query.length),
style:TextStyle(color:Colors.grey)
)]),
)
),
itemCount: suggestionList.length,);
}
}

Open a modal or a dialogue after navigation in Flutter

After calling Navigator pushReplacement, I arrive at a screen where I'd like to open a modal or a dialog automatically after the screen loads. I'm trying to do that using Timer.run inside initState() but it doesn't work, it doesn't show any errors as well. Could anyone help me understand what am I missing here?
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'dart:async';
class AfterSplash extends StatefulWidget {
#override
_AfterSplashState createState() => _AfterSplashState();
}
class _AfterSplashState extends State<AfterSplash> {
void initState() {
super.initState();
Timer.run(() {
showDialog(
context: context,
builder: (_) => AlertDialog(title: Text("Dialog title")),
);
});
}
#override
Widget build(BuildContext context) {
return opacityLogoTitle();
}
}
Widget opacityLogoTitle() {
return Scaffold(
body: Opacity(
opacity: 0.5,
child: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
child: Image(image: AssetImage('assets/images/main.png')),
),
),
),
Text(
'Sample App',
style: TextStyle(
fontFamily: 'SF Pro Display',
fontSize: 60,
color: Color.fromRGBO(105, 121, 248, 1),
),
),
],
),
),
),
);
}
It's my test code with your code.
It works well.
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: AfterSplash(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class AfterSplash extends StatefulWidget {
#override
_AfterSplashState createState() => _AfterSplashState();
}
class _AfterSplashState extends State<AfterSplash> {
void initState() {
super.initState();
Timer.run(() {
showDialog(
context: context,
builder: (_) => AlertDialog(title: Text("Dialog title")),
);
});
}
#override
Widget build(BuildContext context) {
return opacityLogoTitle();
}
}
Widget opacityLogoTitle() {
return Scaffold(
body: Opacity(
opacity: 0.5,
child: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Container(child: Text('asdf')),
),
),
Text(
'Sample App',
style: TextStyle(
fontFamily: 'SF Pro Display',
fontSize: 60,
color: Color.fromRGBO(105, 121, 248, 1),
),
),
],
),
),
),
);
}

EXCEPTION CAUGHT BY GESTURE No MediaQuery widget found. MyHomePage widgets require a MediaQuery widget ancestor

I was trying to add a BottomModelSheet to add new transcations in the transaction list, i follow the and this is the error i am getting, what am i missing here ?
this is my main.dart file
import 'package:expense_tracker/widgets/transaction_list.dart';
import './widgets/transaction_list.dart';
import 'package:flutter/material.dart';
import './widgets/new_transaction.dart';
import './models/transaction.dart';
void main() => runApp(MyHomePage());
class MyHomePage extends StatefulWidget {
// String titleInput;
// String amountInput;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final titleController = TextEditingController();
final amountController = TextEditingController();
final List<Transaction> _userTransactions = [
Transaction(
id: 't1',
title: 'New Shoes',
amount: 1000,
date: DateTime.now(),
),
Transaction(
id: 't2',
title: 'USB Cable',
amount: 600,
date: DateTime.now(),
),
];
void _addNewTransaction(String txTitle, double txAmount) {
final newTX = Transaction(
title: txTitle,
amount: txAmount,
date: DateTime.now(),
id: DateTime.now().toString());
setState(() {
_userTransactions.add(newTX);
});
}
void _startAddNewTransaction(BuildContext ctx) {
showModalBottomSheet(context: ctx,builder: (bCtx) {
return NewTransaction(_addNewTransaction);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter App'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
],
),
body: SingleChildScrollView(
child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: double.infinity,
child: Card(
color: Colors.blue,
child: Text('CHART'),
elevation: 10,
),
),
TransactionList(_userTransactions),
]),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
),
);
}
}
the same BottomModalSheet will be shown while clicking the icon on the appBar and the floatingActionButton in the bottom, they both dont work.
The BuildContext that you're passing to the _startAddNewTransaction method is that of the _MyHomePageState. Since _MyHomePageState contains the MaterialApp (and not the other way round), its BuildContext doesn't know about it.
You have 2 options:
Wrap the widgets that call that method with a Builder widget, whose BuildContext will know about the MaterialApp
Create a new widget (e.g. MyHomePageContent) and pass it to the body: parameter of the material app.
The first option is a quick fix, the second options is the better one.
It would be a good idea to separate your project into multiple files, like so:
main.dart
void main() => runApp(MyApp());
my_app.dart
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
my_home_page.dart
class MyHomePage extends StatefulWidget {
// String titleInput;
// String amountInput;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final titleController = TextEditingController();
final amountController = TextEditingController();
final List<Transaction> _userTransactions = [
Transaction(
id: 't1',
title: 'New Shoes',
amount: 1000,
date: DateTime.now(),
),
Transaction(
id: 't2',
title: 'USB Cable',
amount: 600,
date: DateTime.now(),
),
];
void _addNewTransaction(String txTitle, double txAmount) {
final newTX = Transaction(
title: txTitle,
amount: txAmount,
date: DateTime.now(),
id: DateTime.now().toString());
setState(() {
_userTransactions.add(newTX);
});
}
void _startAddNewTransaction(BuildContext ctx) {
showModalBottomSheet(
context: ctx,
builder: (bCtx) {
return NewTransaction(_addNewTransaction);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter App'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
],
),
body: SingleChildScrollView(
child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
width: double.infinity,
child: Card(
color: Colors.blue,
child: Text('CHART'),
elevation: 10,
),
),
TransactionList(_userTransactions),
]),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
);
}
}

Could not find the correct Provider . The provider you are trying to read is in a different route

I have following route in my app:
Main.dart ---> SplashScreen.dart ---> DetailsPage.dart
Main.dart
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => FontSizeHandler()),
],
child: MyApp(),
),
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SplashScreen(),
);
}
}
From SplashScreen.dart I move to DetailsPage.dart using Navigator.pushAndRemoveUntil i.e
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => DetailsPage()), (route) => false);
Now in Details page on App Bar there is icon and on press of which I want to change the font using FontSizeHandler
DetailsPage.dart
class DetailsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () {
context.read<FontSizeHandler>().increaseFont();
},
),
IconButton(
onPressed: () {
context.read<FontSizeHandler>().decreaseFont();
},
icon: Icon(Icons.arrow_downward),
),
],
title: Text(
"DetailsPage",
style: GoogleFonts.roboto(),
),
),
body: SafeArea(
child: SingleChildScrollView(
child: Card(
child: Container(
padding: EdgeInsets.fromLTRB(5, 5, 5, 15),
child: AutoSizeText(
"MyTexts",
textAlign: TextAlign.justify,
style: GoogleFonts.openSans(
fontSize:
context.watch<FontSizeHandler>().fontSize.toDouble(),
),
),
),
),
),
),
);
}
}
So the problem here is I am getting this error message
Could not find the correct Provider This likely
happens because you used a BuildContext that does not include the
provider
Is this error is due to I used Navigator.pushAndRemoveUntil?
Though I have ChangeNotifierProvider at top of hierarchy why is it throwing error?
How to solve this?
FontSizeHandler.dart
class FontSizeHandler with ChangeNotifier {
int fontSize = 15;
void increaseFont() {
fontSize = fontSize + 2;
notifyListeners();
}
void decreaseFont() {
fontSize = fontSize - 2;
notifyListeners();
}
}
Solved: The Problem Was With Importing Wrong ChangeNotifier class. Never Trust autoimport again
Updated Answer
For reference, the issue was caused by an erroneous import as below:
import 'file:///.../fontchangehandler.dart'; // import 'package:.../fontchangehandler.dart';
Original Answer
Unfortunately I was unable to reproduce the error that you are experiencing using the provided code. If you could provide the rest of the code from the DetailsPage class then that might help to further diagnose the error. I was able to get the example below working which hopefully you might find useful:
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<FontSizeHandler>(
create: (context) {
return FontSizeHandler();
},
),
],
child: MyApp(),
),
);
}
class FontSizeHandler extends ChangeNotifier {
int _fontSize = 15;
int get fontSize => _fontSize;
void increaseFont() {
_fontSize = _fontSize + 2;
notifyListeners();
}
void decreaseFont() {
_fontSize = _fontSize - 2;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SplashScreen(),
);
}
}
class SplashScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: () async {
await Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) {
return DetailsPage();
},
),
(route) => false,
);
},
child: Text('GO TO DETAILS'),
),
),
);
}
}
class DetailsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () {
context.read<FontSizeHandler>().increaseFont();
},
),
IconButton(
onPressed: () {
context.read<FontSizeHandler>().decreaseFont();
},
icon: Icon(Icons.arrow_downward),
),
],
title: Text(
"DetailsPage",
style: GoogleFonts.roboto(),
),
),
body: SafeArea(
child: SingleChildScrollView(
child: Card(
child: Container(
padding: EdgeInsets.fromLTRB(5, 5, 5, 15),
child: AutoSizeText(
"MyTexts",
textAlign: TextAlign.justify,
style: GoogleFonts.openSans(
fontSize: context.watch<FontSizeHandler>().fontSize.toDouble(),
),
),
),
),
),
),
);
}
}

Navigator operation requested with a context that does not include a Navigator

I'm trying to start a new screen within an onTap but I get the following error:
Navigator operation requested with a context that does not include a
Navigator.
The code I am using to navigate is:
onTap: () { Navigator.of(context).pushNamed('/settings'); },
I have set up a route in my app as follows:
routes: <String, WidgetBuilder>{
'/settings': (BuildContext context) => new SettingsPage(),
},
I've tried to copy the code using the stocks sample application. I've looked at the Navigator and Route documentation and can't figure out how the context can be made to include a Navigator. The context being used in the onTap is referenced from the parameter passed into the build method:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
SettingsPage is a class as follows:
class SettingsPage extends Navigator {
Widget buildAppBar(BuildContext context) {
return new AppBar(
title: const Text('Settings')
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: buildAppBar(context),
);
}
}
TLDR: Wrap the widget which needs to access to Navigator into a Builder or extract that sub-tree into a class. And use the new BuildContext to access Navigator.
This error is unrelated to the destination. It happens because you used a context that doesn't contain a Navigator instance as parent.
How do I create a Navigator instance then ?
This is usually done by inserting in your widget tree a MaterialApp or WidgetsApp. Although you can do it manually by using Navigator directly but less recommended. Then, all children of such widget can access NavigatorState using Navigator.of(context).
Wait, I already have a MaterialApp/WidgetsApp !
That's most likely the case. But this error can still happens when you use a context that is a parent of MaterialApp/WidgetsApp.
This happens because when you do Navigator.of(context), it will start from the widget associated to the context used. And then go upward in the widget tree until it either find a Navigator or there's no more widget.
In the first case, everything is fine. In the second, it throws a
Navigator operation requested with a context that does not include a Navigator.
So, how do I fix it ?
First, let's reproduce this error :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
),
);
}
}
This example creates a button that attempts to go to '/' on click but will instead throw an exception.
Notice here that in the
onPressed: () => Navigator.pushNamed(context, "/"),
we used context passed by to build of MyApp.
The problem is, MyApp is actually a parent of MaterialApp. As it's the widget who instantiate MaterialApp! Therefore MyApp's BuildContext doesn't have a MaterialApp as parent!
To solve this problem, we need to use a different context.
In this situation, the easiest solution is to introduce a new widget as child of MaterialApp. And then use that widget's context to do the Navigator call.
There are a few ways to achieve this. You can extract home into a custom class :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHome()
);
}
}
class MyHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
);
}
}
Or you can use Builder :
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
),
),
);
}
}
Hy guys, i have the same problem. This is occur for me. The solution what i found is very simple. Only what i did is in a simple code:
void main() {
runApp(MaterialApp(
home: YOURAPP() ,
),
);
}
I hope was useful.
Make sure your current parent widget not with same level with MaterialApp
Wrong Way
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Title'),
),
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: RaisedButton(
onPressed: () {
//wrong way: use context in same level tree with MaterialApp
Navigator.push(context,
MaterialPageRoute(builder: (context) => ScanScreen()));
},
child: const Text('SCAN')),
)),
),
);
}
}
Right way
void main() => runApp(MaterialApp(
title: "App",
home: HomeScreen(),
));
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Title'),
),
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: RaisedButton(
onPressed: () {
//right way: use context in below level tree with MaterialApp
Navigator.push(context,
MaterialPageRoute(builder: (context) => ScanScreen()));
},
child: const Text('SCAN')),
)),
);
}
}
Just like with a Scaffold you can use a GlobalKey. It doesn't need context.
final _navKey = GlobalKey<NavigatorState>();
void _navigateToLogin() {
_navKey.currentState.popUntil((r) => r.isFirst);
_navKey.currentState.pushReplacementNamed(LoginRoute.name);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: _navKey,
...
);
}
I set up this simple example for routing in a flutter app:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(),
routes: <String, WidgetBuilder>{
'/settings': (BuildContext context) => new SettingsPage(),
},
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('TestProject'),
),
body: new Center(
child: new FlatButton(
child: const Text('Go to Settings'),
onPressed: () => Navigator.of(context).pushNamed('/settings')
)
)
);
}
}
class SettingsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('SettingsPage'),
),
body: new Center(
child: new Text('Settings')
)
);
}
}
Note, that the SettingsPage extends StatelessWidget and not Navigator. I'm not able to reproduce your error.
Does this example help you in building your app? Let me know if I can help you with anything else.
You should rewrite your code in main.dart
FROM:
void main() => runApp(MyApp());
TO
void main() {
runApp(MaterialApp(
title: 'Your title',
home: MyApp(),));}
The point is to have the home property to be your first page
this worked for me, I hope it will help someone in the future
A complete and tested solution:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:my-app/view/main-view.dart';
class SplashView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: Builder(
builder: (context) => new _SplashContent(),
),
routes: <String, WidgetBuilder>{
'/main': (BuildContext context) => new MainView()}
);
}
}
class _SplashContent extends StatefulWidget{
#override
_SplashContentState createState() => new _SplashContentState();
}
class _SplashContentState extends State<_SplashContent>
with SingleTickerProviderStateMixin {
var _iconAnimationController;
var _iconAnimation;
startTimeout() async {
var duration = const Duration(seconds: 3);
return new Timer(duration, handleTimeout);
}
void handleTimeout() {
Navigator.pushReplacementNamed(context, "/main");
}
#override
void initState() {
super.initState();
_iconAnimationController = new AnimationController(
vsync: this, duration: new Duration(milliseconds: 2000));
_iconAnimation = new CurvedAnimation(
parent: _iconAnimationController, curve: Curves.easeIn);
_iconAnimation.addListener(() => this.setState(() {}));
_iconAnimationController.forward();
startTimeout();
}
#override
Widget build(BuildContext context) {
return new Center(
child: new Image(
image: new AssetImage("images/logo.png"),
width: _iconAnimation.value * 100,
height: _iconAnimation.value * 100,
)
);
}
}
As per this comment If your navigator is inside Material context navigator push will give this error. if you create a new widget and assign it to the material app home navigator will work.
This won't work
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text("Title"),
),
body: new Center(child: new Text("Click Me")),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
backgroundColor: Colors.orange,
onPressed: () {
print("Clicked");
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new AddTaskScreen()),
);
},
),
),
);
}
}
This will work
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new HomeScreen());
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Title"),
),
body: new Center(child: new Text("Click Me")),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
backgroundColor: Colors.orange,
onPressed: () {
print("Clicked");
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new AddTaskScreen()),
);
},
),
);
}
}
I was facing the same problem and solved by removing home from MaterialApp and use initialRoute instead.
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => MyApp(),
'/settings': (context) => SettingsPage(),
},
);
And
onTap: () => {
Navigator.pushNamed(context, "/settings")
},
It is Simple
instead using this normal code
`runApp(BasicBankingSystem());`
wrap it with MaterialApp
runApp(MaterialApp(home: BasicBankingSystem()));
It happens because the context on the widget that tries to navigate is still using the material widget.
The short answer for the solution is to :
extract your widget
that has navigation to new class so it has a different context when calling the navigation
When your screen is not navigated from other screen,you don't initially have access to the navigator,Because it is not instantiated yet.So in that case wrap your widget with builder and extract context from there.This worked for me.
builder: (context) => Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
You ca use this plugin
https://pub.dev/packages/get/versions/2.0.2
in The MaterialApp assign property navigatorKey: Get.key,
MaterialApp(
navigatorKey: Get.key,
initialRoute: "/",
);
you can access Get.toNamed("Your route name");
Change your main function example:
void main() {
runApp(
MaterialApp(
title: 'Your title',
home: MyApp(),
)
);
}
use this
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}
instead of this
void main() {runApp(MyApp());}
Wrap with materialapp
reproduce code
import 'dart:convert';
import 'package:flutter/material.dart';
void main() {
// reproduce code
runApp(MyApp());
// working switch //
// runApp(
//
// MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body:
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 100,
width: 100,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => IntroPage(Isscar4: true)),
);
},
child: RichText(
text: TextSpan(
text: 'CAR',
style: TextStyle(
letterSpacing: 3,
color: Colors.white,
fontWeight: FontWeight.w400),
children: [
TextSpan(
text: '4',
style: TextStyle(
fontSize: 25,
color: Colors.red,
fontWeight: FontWeight.bold))
],
)),
),
),
],
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 100,
width: 100,
child: ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => IntroPage(Isscar4: false)),
);
},
child: RichText(
text: TextSpan(
text: 'BIKE',
style: TextStyle(
letterSpacing: 3,
color: Colors.white,
fontWeight: FontWeight.w400),
children: [
TextSpan(
text: '2',
style: TextStyle(
fontSize: 25,
color: Colors.red,
fontWeight: FontWeight.bold))
],
)),
),
),
],
)
])));
}
MaterialApp Swithwidget(istrue) {
return MaterialApp(
home: Scaffold(
body: IntroPage(
Isscar4: istrue,
),
),
);
}
}
class Hi extends StatelessWidget {
const Hi({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Text("df"),
);
}
}
class IntroPage extends StatelessWidget {
final Isscar4;
IntroPage({
Key? key,
required this.Isscar4,
}) : super(key: key);
List<Widget> listPagesViewModel = [];
List<IntroModel> models = [];
#override
Widget build(BuildContext context) {
List<dynamic> intro = fetchIntroApi(Isscar4);
intro.forEach((element) {
var element2 = element as Map<String, dynamic>;
var cd = IntroModel.fromJson(element2);
models.add(cd);
});
models.forEach((element) {
listPagesViewModel.add(Text(""));
});
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(),
));
}
List fetchIntroApi(bool bool) {
var four = bool;
if (four) {
var data =
'[ {"name_Title": "title name1","description": "description1"}, {"name_Title": "title name2","description": "description2"}, {"name_Title": "title name3","description": "description3"}, {"name_Title": "title name4","description": "description4"} ]';
return json.decode(data);
} else {
var data =
'[ {"name_Title": "title name","description": "description1"}, {"name_Title": "title name2","description": "description2"}, {"name_Title": "title name3","description": "description3"} ]';
return json.decode(data);
}
}
}
class IntroModel {
String? nameTitle;
String? description;
IntroModel({this.nameTitle, this.description});
IntroModel.fromJson(Map<String, dynamic> json) {
nameTitle = json['name_Title'];
description = json['description'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name_Title'] = this.nameTitle;
data['description'] = this.description;
return data;
}
}
class Splash extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Splash Screen',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyState(),
debugShowCheckedModeBanner: false,
);
}
void main() {
runApp(Splash());
}
class MyState extends StatefulWidget{
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyState> {
#override
void initState() {
super.initState();
Timer(Duration(seconds: 3),
()=>Navigator.pushReplacement(context,
MaterialPageRoute(builder:
(context) =>
Login()
)
)
);
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center ,
children: [
Container(
child:
Image.asset("assets/images/herosplash.png"),
),
],
),
);
}
}
Builder(
builder: (context) {
return TextButton(
child: const Text('Bearbeiten'),
onPressed:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const gotothesiteyouwant()),
);
});
}
),
Here, all you need is to make MaterialApp the parent of your Build. This is because the context that you've used to navigate to a different screen is finding a MaterialApp or a WidgetApp as a parent of the build.
And Since in your case, the situation is the opposite, therefore you need to modify it by either calling a new Stateless widget the parent of is the MaterialApp or by simply using a Builder as home: Builder in MaterialApp.
Hope this would help!