How solve problem Appbar icon clicked to navigate - flutter

I try to develop flutter application. In this application I used Appbar with user icon to navigate another page.
Now I am clicked that icon(person icon) it shows error.
.
It has not proper documentation though internet. I couldn't found answer. My source code is
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text("Web Issue finder"),
actions: <Widget>[
new IconButton(
icon: Icon(Icons.person),
// tooltip: "Admin",
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (_) => AdminAuth()),
);
}
)
],
),
body: new FutureBuilder(
future: loadStates(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
itemBuilder: (context, index) {
if (index >= snapshot?.data?.length ?? 0) return null;
return new ListTile(
title: new Text("${snapshot.data[index]}"),
onTap: () {
debugPrint("${snapshot.data[index]} clicked");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
IssueAddScreen(state: snapshot.data[index]),
),
);
},
);
},
);
} else {
return new Center(child: new CircularProgressIndicator());
}
})));
}
this is navigated class
import 'package:flutter/material.dart';
class AdminAuth extends StatelessWidget{
// final String state;
// IssueAddScreen({Key key, #required this.state}) : super(key: key);
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "iWallet",
home: Scaffold(
appBar: AppBar(title: Text("admin auth"),),
body: Text("cvgbh"),
),
);
}
}
Still I can't fix that error I am followed some documentation and stack overflow questions.
flutter documenttation
Github question and answer
Stackoverflow question and answer

Try to use context in your builder
Navigator.push(context,MaterialPageRoute(builder: (BuildContext context){return AdminAuth();
});

The issue here is with Navigator not present in the parent context.
You are using a context for the MyApp which isn't under the navigator.
MyApp <------ context
--> MaterialApp
(--> Navigator built within MaterialApp)
--> Scaffold
--> App Bar
--> ...
to solve this - Define new class that contain MaterialApp then pass MyApp() in home: of MaterialApp.
Same for the AdminAuth.
class MyAppHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyApp(),
);
}
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text("Web Issue finder"),
actions: <Widget>[
new IconButton(
icon: Icon(Icons.person),
// tooltip: "Admin",
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => AdminAuth()),
);
})
],
),
body: new FutureBuilder(
future: loadStates(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
itemBuilder: (context, index) {
if (index >= snapshot?.data?.length ?? 0) return null;
return new ListTile(
title: new Text("${snapshot.data[index]}"),
onTap: () {
debugPrint("${snapshot.data[index]} clicked");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
IssueAddScreen(state: snapshot.data[index]),
),
);
},
);
},
);
} else {
return new Center(child: new CircularProgressIndicator());
}
}));
}
}

The problem is the one explained above.
In my own words:
The context from which you are calling "Navigator" does not contain a "Navigator".
I guess the problem is that in you code you call Scaffold before MaterialApp complete the build method and get a Navigator or something like that.
If you separate the MaterialApp and the Scaffold (like below) you solve the problem.
void main() => runApp(MaterialApp(
home: MyApp())
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Web Issue finder"),
actions: <Widget>[
new IconButton(
icon: Icon(Icons.person),
tooltip: "Admin",
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (_) => AdminAuth()),
);
}
)
],
),
body: new FutureBuilder(
future: loadStates(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
itemBuilder: (context, index) {
if (index >= snapshot?.data?.length ?? 0) return null;
return new ListTile(
title: new Text("${snapshot.data[index]}"),
onTap: () {
debugPrint("${snapshot.data[index]} clicked");
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
IssueAddScreen(state: snapshot.data[index]),
),
);
},
);
},
);
} else {
return new Center(child: new CircularProgressIndicator());
}
})));

There is some issue with MateriaApp context in the library.
Your code will not work. Create a different MaterialApp and then use your widget in home: property of MaterialApp.
For example:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.lightBlue,
),
home: MyAppState(), //This is your MyAppState
);
}
}
Now you can remove MaterialApp widget in your MyAppState keeping only Scaffold Widget

IconButton(onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(builder: (context)=> AdminAuth));
},)

Related

How to Passing Data from Navigator Pop to Previous Page Where The Data is Used in The Widget Inside the ListView.builder

As stated in the title. How to return data to the previous page where the data is used to list widgets.
I have read this article Flutter Back button with return data or other similar articles. The code works perfectly. But there is a problem if I want to use the data returned to the widget that is in the list.\
Note that I only want to update one ListWidget, I don't want to refresh the state of the entire HomePage like the solution in this article Flutter: Refresh on Navigator pop or go back.
Here is a simple code sample to represent the problem I'm facing.
(check on ListWidget Class and SecondPage Class below)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
HomePage class
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: ListView.builder(
itemCount: 4,
itemBuilder: (_, index){
return ListWidget(number: index+1);
},
)
),
);
}
}
ListWidget Class
class ListWidget extends StatelessWidget{
ListWidget({#required this.number});
final int? number;
String? statusOpen;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () async {
statusOpen = await Navigator.of(context, rootNavigator: true)
.push(
MaterialPageRoute(
builder: (BuildContext context) => SecondPage(),
),
);
},
child: Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(20),
color: Colors.amber,
child: Text(statusOpen != null ? '$number $statusOpen' : '$number Unopened'),
//
// I want to change the text here to 'has Opened' when the user returns from SecondPage
//
),
);
}
}
SecondPage Class
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context, 'has Opened');
// return 'has Opened' to await statusOpen variable
},
child: Text('Go Back'),
),
),
);
}
}
is there any solution to handle this?
If you make your listWidget a stateful widget, then you can get the solution where you just need to call setState when you return to your previous screen. And in this way you will be only changing your single list element and not the full screen.
sample code:
changing this line- class ListWidget extends StatefulWidget
and adding these lines -
onTap: () async {
statusOpen = await Navigator.of(context, rootNavigator: true)
.push(
MaterialPageRoute(
builder: (BuildContext context) => SecondPage(),
),
);
setState(() {
});
},
If you used the data in your listview just call setstate after Navigator.pop like below code
onTap: () async {
statusOpen = await Navigator.of(context, rootNavigator: true)
.push(
MaterialPageRoute(
builder: (BuildContext context) => SecondPage(),
),
).then((value) async {
setState(() {});
});
},

Navigation problem with FutureBuilder and MaterialApp

My app has a state which is computed as a Future.
For example it includes a theme color, because I want to change the color when I navigate.
I try to display a progress indicator while waiting for the data.
But I can't make it work.
Either Navigator.push is not working and the app bar is missing, or I have no progress indicator and a route error...
Here is a code snippet.
import 'package:flutter/material.dart';
void main() => runApp(Test());
class Test extends StatefulWidget {
#override
State<StatefulWidget> createState() => _TestState();
}
class _TestState extends State<Test> {
Future<Color> color = Model.getColor();
#override
Widget build(BuildContext context) {
return FutureBuilder<Color>(
future: color,
builder: (context, snapshot) {
if (snapshot.hasError) throw snapshot.error;
if (snapshot.connectionState != ConnectionState.done) {
if (false) {
// Navigation not working. App bar missing.
return Material(child: Center(child: CircularProgressIndicator()));
} else {
// Progress not working. Screen flickering.
return MaterialApp(home: _buildWait());
}
}
var app = MaterialApp(
theme: ThemeData(primaryColor: snapshot.data),
home: _buildPage(),
// ERROR: The builder for route "/" returned null.
// routes: {'/': (_) => _buildPage()},
);
return app;
},
);
}
Widget _buildPage() {
return Builder(
builder: (context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: RaisedButton(
child: Text('Push'),
onPressed: () {
setState(() {
color = Model.getColor();
});
Navigator.push(context, MaterialPageRoute(builder: (context) {
return Scaffold(appBar: AppBar());
}));
},
),
),
);
},
);
}
}
Widget _buildWait() {
return Scaffold(
appBar: AppBar(title: Text('Wait...')),
body: Center(child: CircularProgressIndicator()),
);
}
class Model {
static final _colors = [Colors.red, Colors.green, Colors.amber];
static int _index = 0;
static Future<Color> getColor() {
return Future.delayed(Duration(seconds: 2), () => _colors[_index++ % _colors.length]);
}
}
Expected result: when I push the button to navigate to the new route, it should display a progress indicator, and then the new screen with a different theme color.
Now try the following. Try to make a root widget separately, because root widget is always there. you don't want a complete UI route to persist in the memory. Also make next route as a separate widget.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Test(),
);
}
}
class Test extends StatefulWidget {
#override
State<StatefulWidget> createState() => _TestState();
}
class _TestState extends State<Test> {
Future<Color> color = Model.getColor();
#override
Widget build(BuildContext context) {
return FutureBuilder<Color>(
future: color,
builder: (context, snapshot) {
if (snapshot.hasError) return Center(child: Text("An Error Occurred"));
if (snapshot.connectionState == ConnectionState.waiting) {
return _buildWait();
}
var app = Theme(
data: ThemeData(primaryColor: snapshot.data),
child: _buildPage(),
);
return app;
},
);
}
Widget _buildPage() {
return Scaffold(
appBar: AppBar(),
body: Center(
child: RaisedButton(
child: Text('Push'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return NextRoute();
}));
},
),
),
);
}
}
Widget _buildWait() {
return Scaffold(
appBar: AppBar(title: Text('Wait...')),
body: Center(child: CircularProgressIndicator()),
);
}
class Model {
static final _colors = [Colors.red, Colors.green, Colors.amber];
static int _index = 0;
static Future<Color> getColor() {
return Future.delayed(
Duration(seconds: 2), () => _colors[_index++ % _colors.length]);
}
}
class NextRoute extends StatefulWidget {
NextRoute({Key key}) : super(key: key);
#override
_NextRouteState createState() => _NextRouteState();
}
class _NextRouteState extends State<NextRoute> {
#override
Widget build(BuildContext context) {
return FutureBuilder<Color>(
future: Model.getColor(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text("An Error Occurred"),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return _buildWait();
}
return Theme(
data: ThemeData(primaryColor: snapshot.data),
child: Scaffold(
appBar: AppBar(),
),
);
});
}
}
so I think I have found the error, actually you must have an MaterialApp inside runApp() as root.
so you can't have MaterialApp inside FutureBuilder
what you can do is make MaterialApp the root widget and have a default Home Screen and inside its build method you can have your FutureBuilder but again don't include materialApp inside it just use Scaffold directly.
EDIT :
To answer the question regarding app theme
You can have switching themes by using
theme and darkTheme in materialApp And control themeMode from Provider or any other state management approach.
MaterialApp(
title: 'Flutter Tutorials',
debugShowCheckedModeBanner: false,
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: appState.isDarkModeOn ? ThemeMode.dark : ThemeMode.light,
home: ThemeDemo(),
);
There are several ways to do it here is one more that I found custom theme app
Try this out it will work, if doesn't let me know
I think you can do as follow:
Move all Future data/FutureBuilder into different Stateless/Stateful Widget and override the theme color with Theme class
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var color = Theme.of(context).primaryColor;
return FutureBuilder(
future: Model.getColor(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Theme(
data: ThemeData(primaryColor: color),
child: _buildWait(),
);
} else {
color = snapshot.data;
return Theme(
data: ThemeData(primaryColor: color),
child: Scaffold(
appBar: AppBar(),
),
);
}
},
);
}
}
The first page use the local variable to store color
...
Color _primaryColor;
#override
void initState() {
_primaryColor = Theme.of(context).primaryColor;
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(primaryColor: _primaryColor),
home: _buildPage(),
);
}
...
If you want the first page update the theme on the same time, you should use some method to share data between widget (e.g. Provider). I use the simple method to catch the custom return value
// First Page
// use "then" can get the return value from the other route
...
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
})).then((color) {
setState(() {
_primaryColor = color;
});
});
},
...
// Second Page
// WillPopScope can catch navigator pop event
...
return WillPopScope(
onWillPop: () async {
Navigator.of(context).pop(color);
return Future.value(false);
},
child: FutureBuilder(
...
If it is not necessary for you to use Routing when you try to change Theme,
I can provide a simple solution that change the theme data by Theme class
ThemeData currentTheme;
#override
void initState() {
super.initState();
currentTheme = Theme.of(context);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder<Color>(
future: color,
builder: (context, snapshot) {
Widget child;
if (snapshot.hasError) throw snapshot.error;
if (snapshot.connectionState != ConnectionState.done) {
child = Scaffold(
appBar: AppBar(),
body: const Center(child: CircularProgressIndicator()),
);
}else{
currentTheme = currentTheme.copyWith(primaryColor: snapshot.data);
child = _buildPage();
}
return Theme(
data: currentTheme,
child: child,
);
},
),
);
}
Here is the document of Themes for part of an application
I have removed the return Builder section in the _buildPage widget and it seems to work. It also shows the CircularProgressIndıcator and Wait... text in AppBar.
Here is the edited code:
Widget _buildPage() {
return Scaffold(
appBar: AppBar(),
body: Center(
child: RaisedButton(
child: Text('Push'),
onPressed: () {
setState(() {
color = Model.getColor();
});
Navigator.push(context, MaterialPageRoute(builder: (context) {
return Scaffold(appBar: AppBar());
}));
},
),
),
);
}

Flutter - Could not find the correct Provider

I've got an app having file structure like this: main -> auth -> home -> secret. Key codes are as below:
For main.dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>.value(value: AuthService().user),
ChangeNotifierProvider(create: (context) => SecretProvider()),
],
child: MaterialApp(
title: 'My Secrets',
home: AuthScreen(),
),
);
}
}
For home.dart:
class HomeScreen extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
var secretProvider = Provider.of<SecretProvider>(context);
return ChangeNotifierProvider(
create: (context) => SecretProvider(),
child: Scaffold(
appBar: AppBar(
// some codes...
),
body: StreamBuilder<List<Secret>>(
stream: secretProvider.secrets,
builder: (context, snapshot) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 15.0),
child: ListView.separated(
// return 0 if snapshot.data is null
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.web),
title: Text(snapshot.data[index].title),
trailing: Icon(Icons.edit),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecretScreen(
secret: snapshot.data[index],
),
),
);
},
);
},
separatorBuilder: (context, index) {
return Divider();
},
),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecretScreen()),
);
},
),
),
);
}
}
For secret.dart:
class SecretScreen extends StatefulWidget {
final Secret secret;
SecretScreen({this.secret});
#override
_SecretScreenState createState() => _SecretScreenState();
}
class _SecretScreenState extends State<SecretScreen> {
// some codes...
#override
void initState() {
final secretProvider = Provider.of<SecretProvider>(context, listen: false);
// some codes...
super.initState();
}
#override
void dispose() {
// some codes...
super.dispose();
}
#override
Widget build(BuildContext context) {
final secretProvider = Provider.of<SecretProvider>(context);
return Scaffold(
// some codes...
);
}
}
These codes worked just fine, but later on I decided to move the ChangeNotifierProvider from main.dart to home.dart due to some class instance life cycle issue. The new code is like below:
For main.dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>.value(value: AuthService().user),
],
child: MaterialApp(
title: 'My Secrets',
home: AuthScreen(),
),
);
}
}
For home.dart:
class HomeScreen extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
// var secretProvider = Provider.of<SecretProvider>(context);
return ChangeNotifierProvider(
create: (context) => SecretProvider(),
child: Consumer<SecretProvider>(
builder: (context, secretProvider, child) {
return Scaffold(
appBar: AppBar(
// some codes...
),
body: StreamBuilder<List<Secret>>(
stream: secretProvider.secrets,
// stream: SecretProvider().secrets,
builder: (context, snapshot) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 15.0),
child: ListView.separated(
// return 0 if snapshot.data is null
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.web),
title: Text(snapshot.data[index].title),
trailing: Icon(Icons.edit),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecretScreen(
secret: snapshot.data[index],
),
),
);
},
);
},
separatorBuilder: (context, index) {
return Divider();
},
),
);
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecretScreen()),
);
},
),
);
},
),
);
}
}
Basically, I just moved the ChangeNotifierProvider to home.dart and used a Consumer to pass the context, but this time, whenever I navigate to secret screen, it prompts me error like below:
Could not find the correct Provider<SecretProvider> above this SecretScreen Widget
This likely happens because you used a `BuildContext` that does not include the provider
of your choice.
This BuildContext is really bugging me. Even if I'm having ChangeNotifierProvider one level lower than before, the SecretScreen widget should still be aware of the SecretProvider that passed on from HomeScreen because it's still the child of HomeScreen and according to my knowledge, the context should contain the SecretProvider.
You get this error because your SecretProvider instance is part of HomeScreen which is not a parent of SecretScreen.
In order, when you push a new page, this new page is not a descendent of the previous one so you can't access to inherited object with the .of(context) method.
Here the a schema representing the widget tree to explain the situation :
With a Provider on top of MaterialApp (the navigator) :
Provider
MaterialApp
HomeScreen -> push SecretScreen
SecretScreen -> Here we can acces the Provider by calling Provider.of(context) because the context can access to its ancestors
With a Provider created in HomeScreen :
MaterialApp
HomeScreen -> push SecretScreen
Provider -> The provider is part of HomeScreen
SecretScreen -> The context can't access to the Provider because it's not part of its ancestors
I hope my answer is pretty clear and will help you to understand what happens ;)

How can i use flutter drawer menu in page routing?

i am new to flutter also coding.
what i want to do:
to add drawer menu to main.dart, it will return Scaffold for all pages in the menu.
in every page i want to use different Scaffold. (appbar & body)
i created pages, routes, drawer; but i couldn't add drawer to pages and also in the Builder(main.dart), i think i have some mistakes.
main.dart is like this:
import 'package:flutter/material.dart';
import 'package:letter_app/screens/user/postbox.dart';
import 'package:letter_app/screens/user/unread.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
int selectedMenuItem = 0;
final pageOptions = [
PostBox(),
Unread(),
];
Widget buildDrawer(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(),
),
ListTile(
title: Text('Unread'),
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => new Unread()));
Navigator.pop(context);
},
),
ListTile(
title: Text('Post Box'),
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => new PostBox()));
Navigator.pop(context);
},
),
],
),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'New App',
theme: ThemeData.dark(),
routes: <String, WidgetBuilder>{
'/screens/user/unread.dart': (BuildContext context) => Unread(),
'/screens/user/postbox.dart': (BuildContext context) => PostBox(),
},
home: Builder(
builder: (context) => Scaffold(
drawer: buildDrawer(context),
body: Container(child: pageOptions[selectedMenuItem]),
),
),
);
}
}
unread.dart is like this:
import 'package:flutter/material.dart';
class Unread extends StatefulWidget {
#override
_UnreadState createState() => _UnreadState();
}
class _UnreadState extends State<Unread> {
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: ,
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: Text('Unread'),
),
);
}
}
Just define the buildDrawer widget in a seperate dart file, import the file. Then, just assign it to every Scaffold.

Flutter: How to restore ListView position?

When routing master ListView and its detail ItemView with Navigator, scroll position of the ListView was lost on back stack.
How to restore ListView scroll position?
Reusing ListView widget also lost position - also do not see reusing Widget in flutter example.
Sample code as request by Rainer,
Widget build(BuildContext context) {
return new MaterialApp(
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => new MyListView(),
},
onGenerateRoute: (RouteSettings s) {
final List<String> paths = name.split('/');
...
return new new ItemView(paths[1])
}
}
In MyListView, when ItemRow.onTab => Navigator.pushNamed(c, '/item/1').
In ItemView back button call Navigator.pushNamed('/');
Both Widget are stateful
This should work. Here is some sample code.
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
home: new MyHomePage(),
));
}
class MyHomePage extends StatelessWidget {
Widget build(BuildContext context) {
return new Scaffold(
body: new ListView(
children: new List.generate(100, (int index) {
return new ListTile(
title: new Text('Item $index'),
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) {
return new Scaffold(
body: new Center(
child: new RaisedButton(
child: new Text('Pop!'),
onPressed: () => Navigator.pop(context),
),
),
);
},
),
);
},
);
},
),
),
);
}
}
Make sure you're using Navigator.pop() instead of Navigator.pushNamed('/'); to go back. If it doesn't work, please post more of your code or file an issue.