My internship boss asked me to solve a problem which I am not being able to do so far.
I have been given an ready application. This is basically flattered attendance app.
Now let me tell you clearly where I'm facing the issue.When the user click the student button,It takes the student to a class page,And in the class pledge the user or the student has to select the class by onTap event-One tapped and selected the class.the You, the user, goes to another page where the user will need to tap again to finally go to the check in Page-meaing another OnTap event./
Now my boss wants to get rid of the two OnTap events in the in between.He wants me to directly grow from student button to Student Item Page without losing the contents of the object that was passed. Please note I just show the important codes here scrapping the UI codes because it will become long.Please see if you can understand the codes.
The app uses bloc/statemanagement system.
Student Button-From here starts the flow(only important codes here)
final User user;
SelectUser({this.user});
Expanded(
child: GestureDetector(
onTap: () {
final ClassroomRepository classroomRepository =
ClassroomRepository(
classroomApiClient: ClassroomApiClient(
httpClient: http.Client(),
),
);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BlocProvider(
create: (context) => ClassroomBloc(
classroomRepository: classroomRepository),
child: ClassList(user: this.user),//user object is passed to the ClassList
)));
},
child: Image.asset('assets/logos/studentbutton.png'),
)
The above is passing the user object to ClassList. Below is the full code for ClassList:
class ClassList extends StatelessWidget {
final User user ;
ClassList({this.user});
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: BlocBuilder<ClassroomBloc, ClassroomState>(
builder: (context, state) {
if (state is ClassroomEmpty) {
print('load');
BlocProvider.of<ClassroomBloc>(context)
.add(FetchClassroom(schoolId: this.user.id));
return Center(child: Text('Please Wait'));
} else if (state is ClassroomLoading) {
return Center(child: CircularProgressIndicator());
} else if (state is ClassroomLoaded) {
final classrooms = state.classrooms;
return ListView.builder(
itemCount: classrooms.length,
itemBuilder: (context, position) {
return ClassItem(classroom: classrooms[position]);//GENERATES UI WITH ONTAP EVENT IN THE NEXT PAGE.
},
);
} else {
return Text(
'Something went wrong!',
style: TextStyle(color: Colors.red),
);
}
},
),
));
}
}
Now , it will go to Class ItemPage to perform the first onTap. You can see in the above code(return ClassItem(classroom: classrooms[position]) passing classroom object from repo)
Below is the full code for Class Item Page. HERE , I AM TRYING TO GET RID OF THIS ON TAP BUTTON WITHOUT LOSING THE CONTENT OF THE OBJECT THAT IS PASSED BUT FAILED REPEATEDLY.
import 'package:attendanceapp/blocs/student/blocs.dart';
import 'package:attendanceapp/repositories/student/repositories.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:attendanceapp/models/classroom.dart';
import 'package:attendanceapp/widgets/student/student.dart';
class ClassItem extends StatelessWidget {
final Classroom classroom ;
ClassItem({this.classroom});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
final VisitorRepository studentRepository = VisitorRepository(
visitorApiClient: StudentApiClient(
httpClient: http.Client(),
),
);
Navigator.push(context,
MaterialPageRoute(builder: (context) =>
BlocProvider(
create: (context) => StudentBloc(studentRepository:studentRepository),
child: Student(classroom: classroom),
)
)
);
},//tapping on the card
child: Card(
margin: EdgeInsets.all(20),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Text(classroom.classroomName,style: TextStyle(fontSize: 30))
)
),
);
}
}
From ClassItem Page , we go to the StudentPage passing ClassRooms as object.//Shows the Appbar and generates UI by returning the next page. Now this is the Page I don’t want to show but only pass the objects.
class Student extends StatelessWidget {
final Classroom classroom ;
Student({this.classroom});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
backgroundColor: Colors.amber[600],
title: Text(classroom.classroomName),
),
body:
Center(
child: BlocBuilder<StudentBloc, StudentState>(
builder: (context, state) {
if (state is StudentEmpty) {
print(this.classroom);
BlocProvider.of<StudentBloc>(context).add(FetchStudent(classId: this.classroom.id));
return Center(child: Text('Please Wait'));
} else if (state is StudentLoading) {
return Center(child: CircularProgressIndicator());
} else if (state is StudentLoaded) {
final students = state.students;
return ListView.builder(
itemCount: students.length,
itemBuilder: (context, position) {
return StudentItem(student:students[position], classroom: classroom,);
},
);
} else {
return Text(
'Something went wrong!',
style: TextStyle(color: Colors.red),
);
}
},
),
));
}
}
Finally, we go from StudentButton Page to StudeDetails Page. Below IS THE SECOND onTap in the studentItem page which I want to get rid. But failed …I want to go From Student Button Page to STUDENT ITEM PAGE without two OnTap evens and Not losing the content of the object. I have been trying for 7 days,but failed. I told my internship boss it is possible because each student has a class but he said do it any how.
Below is the next page we were talking about in the previous page.
I just need to show StudentDetails page starting from studentButton without performing the two onTaps. I have struggling with this for about 7 days, but still couldn’t go from studentButton to studentDetails page skipping the intermittent pages.
class StudentItem extends StatelessWidget {
final Student student;
final Classroom classroom;
StudentItem({this.student, this.classroom});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
final StudentAttendanceRepository attendanceRepository =
StudentAttendanceRepository(
studentAttendanceClient: StudentAttendanceClient(
httpClient: http.Client(),
),
);
Navigator.push(
context,
MaterialPageRoute(
settings: RouteSettings(name: '/studentDetail'),
builder: (context) => BlocProvider(
create: (context) => StudentAttendanceBloc(studentAttendanceRepository: attendanceRepository),
child: StudentDetail(student: student,),
),
),
).then((value){
if(value){
BlocProvider.of<StudentBloc>(context).add(FetchStudent(classId: this.classroom.id));
}
});
},
////UI CODES HERE…NOT PASTED HERE BECAUSE TOO LONG
}
So to access the data on different pages, you can pass the data to your event from page 1 and then in the bloc, you can assign this data to one of the state class. Now on page 2 or page 3, wherever you want to access the data, you can use BlocListener or BlocBuilder and access the data using the state object.
I'm trying to move from Provider to GetX and am stuck on how GetX.find() works.
We have a restaurant app with a few tables. Below is the narrowed down view of my old Provider code showing just the staff table and VIP table. You click on the "Seat" button to mark the table as seated.:
Widget build(BuildContext context) {
return MaterialApp(
title: 'Restaurant',
home: Column(children: [
ChangeNotifierProvider<Table>( //Provider
create: (_) => Table("Staff"), //create controller
child: Builder(builder: (context) {
return Column(children: [
Text("Staff seated: ${context.watch<Table>().seated}"), //consume changes
ElevatedButton(
child: const Text("Seat Staff"),
onPressed: () {
context.read<Table>().toggleSeated(); //call controller
}),
]);
}),
),
ChangeNotifierProvider<Table>(. //Provider
create: (_) => Table("VIP"), //create controller
child: Builder(
builder: (context) {
return Column(children: [
Text("VIP seated: ${context.watch<Table>().seated}"), //consume changes
ElevatedButton(
child: const Text("Seat VIP"),
onPressed: () {
context.read<Table>().toggleSeated(); //call controller
}),
]);
},
)),
]),
);
}
}
and associated narrowed down controller:
class Table extends ChangeNotifier {
final String name;
int chairs = 0;
bool seated = false;
Table(this.name);
toggleSeated() {
seated = !seated;
notifyListeners(); //notify providers
}
}
Now here is the GetX code (which compiles fine) but I tried t.toggle and Get.find<Table>().toggle and both functions toggle both tables at the same time. In the old code they toggled the tables individually:
Widget build(BuildContext context) {
return MaterialApp(
title: 'Restaurant',
home: Column(
children: [
GetBuilder( //GetX
init: Table("Staff"), //create controller
builder: (Table t) {
return Column(children: [
Text("Staff seated: ${t.seated}"), //consume changes
ElevatedButton(
child: const Text("Seat Staff"),
onPressed: () {
//I've tried Get.find here
Get.find<Table>().toggleSeated(); //call controller
},
),
]);
},
),
GetBuilder(. //GetX
init: Table("VIP"), //create controller
builder: (Table t) {
return Column(children: [
Text("VIP seated: ${t.seated}"), //consume changes
ElevatedButton(
child: const Text("Seat VIP"),
onPressed: () {
//I've also tried directly using the controller
t.toggleSeated(); //call controller
},
),
]);
},
),
],
));
}
and associated narrowed down controller:
class Table extends GetxController {
final String name;
int chairs = 0;
bool seated = false;
Table(this.name);
toggleSeated() {
seated = !seated;
update(); //notify GetX
}
}
In the Provider version I can interact with the tables individually but in the GetX version the button seems to act on all tables regardless of whether I use Get.find<Table>() or directly using the controller's t.toggle.
Controllers are created per type, but you can add 'tag' to create separate controllers. Also you need to add the controller to Get to have proper lifecycle:
Get.put(Table())
Like you have 'Staff' and 'VIP' you can pass that as a tag:
Get.put(Table(), tag: 'Staff')
GetX Controllers automatically released when the caller disposed so in your case when you leave the given page.
You can find the 'Staff' Controller downstream with Get.find(tag:'Staff');
You need to use an instance of Table just like package example. you can't directly use it on your screen.
Controller controller = Get.put(Table());
// ↑ declare controller inside build method
You can check Baker's answer too.
Hello I am new to flutter and I have a problem to update the list after executing a deleting an item from the database. Some said to use setState, but I still don't know how to implement it in my code. Tried to call seState right after the delete action, but still nothing happened. Still have some trouble to understand which component to update in Flutter. Thank you.
class ProfileView extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ProfileViewState();
}
}
class _ProfileViewState extends State<ProfileView> {
late Future<List<Patient>> _patients;
late PatientService patientService;
#override
void initState() {
super.initState();
patientService = PatientService();
_patients = patientService.getPatient();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Profile')),
body: Column(
children: <Widget>[
Flexible(
child: SizedBox(
child: FutureBuilder<List<Patient>>(
future: _patients,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasError) {
print(snapshot);
return Center(
child: Text("Error"),
);
} else if (snapshot.hasData){
List<Patient> patients = snapshot.data;
return _buildListView(patients);
} else {
return Center(
child: Container(),
);
}
},
),
),
)
],
),
);
}
Widget _buildListView(List<Patient> patients) {
return ListView.separated(
separatorBuilder: (BuildContext context, int i) => Divider(color: Colors.grey[400]),
itemCount: patients.length,
itemBuilder: (context, index) {
Patient patient = patients[index];
return Row(
children: <Widget>[
Flexible(
child: SizedBox(
child: ListTile(
title: Text(patient.firstName),
subtitle: Text(patient.phone),
trailing: IconButton(
icon: new Icon(const IconData(0xf4c4, fontFamily: 'Roboto'), size: 48.0, color: Colors.red),
onPressed: () {
patientService.deletePatient(patient.id.toString());
}),
),
)
)
],
);
}
);
}
}
You can achieve that by removing the initialization of the future from the initState and simply give the future of patientService.getPatient() to the FutureBuilder, like this:
future: patientService.getPatient()
And call setState after making sure the patient have been successfully deleted.
The explanation behind doing that is when you delete your patient from the DB, yes it is removed from there, but the UI didn't get an update about the list of patients after the delete. And the reason why calling setState in your case doesn't make a change is because you are assigning the future in initState which is called once and only once when the widget is initialized. So when you call setState the future won't be called again hence no new data is fetched.
So what I did is just remove the initialization of the future from initState and give it to the FutureBuilder, which will be rebuild whenever you call setState.
Even though this works, it isn't the ideal solution. Because you are rebuilding your whole widget every time a delete is made which is kinda of heavy considering the FutureBuilder, so what I suggest is checking out some state mangement solutions like Bloc or Mobx or even the Provider package (which isn't a state mangement according to its creator).
Hope that makes clear !
Happy coding !
call setState() inside the onPressed method.
onPressed: () {
patientService.deletePatient(patient.id.toString());
setState((){});
}),
If you are not saving a local copy of the list from which you are deleting an item then this works
Although if the delete method deletes on from wherever you are fetching the items then you will need to call
_patients = patientService.getPatient();
before calling setState()
I think your deletePatient is asynchronous method. And you are calling this method without await and after this function setState is called thus widget is getting updated before delete is completed.
If deletePatient is asynchronous then add await before calling it and add setState after it.
onPressed: () async {
await patientService.deletePatient(patient.id.toString());
setState((){});
})
I have one StatefulWidget in Flutter with button, which navigates me to another StatefulWidget using Navigator.push(). On second widget I'm changing global state (some user preferences). When I get back from second widget to first, using Navigator.pop() the first widget is in old state, but I want to force it's reload. Any idea how to do this? I have one idea but it looks ugly:
pop to remove second widget (current one)
pop again to remove first widget (previous one)
push first widget (it should force redraw)
There's a couple of things you could do here. #Mahi's answer while correct could be a little more succinct and actually use push rather than showDialog as the OP was asking about. This is an example that uses Navigator.push:
import 'package:flutter/material.dart';
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: Column(
children: <Widget>[
RaisedButton(
onPressed: () => Navigator.pop(context),
child: Text('back'),
),
],
),
);
}
}
class FirstPage extends StatefulWidget {
#override
State<StatefulWidget> createState() => new FirstPageState();
}
class FirstPageState extends State<FirstPage> {
Color color = Colors.white;
#override
Widget build(BuildContext context) {
return new Container(
color: color,
child: Column(
children: <Widget>[
RaisedButton(
child: Text("next"),
onPressed: () async {
final value = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage()),
),
);
setState(() {
color = color == Colors.white ? Colors.grey : Colors.white;
});
},
),
],
),
);
}
}
void main() => runApp(
MaterialApp(
builder: (context, child) => SafeArea(child: child),
home: FirstPage(),
),
);
However, there's another way to do this that might fit your use-case well. If you're using the global as something that affects the build of your first page, you could use an InheritedWidget to define your global user preferences, and each time they are changed your FirstPage will rebuild. This even works within a stateless widget as shown below (but should work in a stateful widget as well).
An example of inheritedWidget in flutter is the app's Theme, although they define it within a widget instead of having it directly building as I have here.
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
ColorDefinition.of(context).toggleColor();
Navigator.pop(context);
},
child: new Text("back"),
),
],
),
);
}
}
class ColorDefinition extends InheritedWidget {
ColorDefinition({
Key key,
#required Widget child,
}): super(key: key, child: child);
Color color = Colors.white;
static ColorDefinition of(BuildContext context) {
return context.inheritFromWidgetOfExactType(ColorDefinition);
}
void toggleColor() {
color = color == Colors.white ? Colors.grey : Colors.white;
print("color set to $color");
}
#override
bool updateShouldNotify(ColorDefinition oldWidget) =>
color != oldWidget.color;
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var color = ColorDefinition.of(context).color;
return new Container(
color: color,
child: new Column(
children: <Widget>[
new RaisedButton(
child: new Text("next"),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new SecondPage()),
);
}),
],
),
);
}
}
void main() => runApp(
new MaterialApp(
builder: (context, child) => new SafeArea(
child: new ColorDefinition(child: child),
),
home: new FirstPage(),
),
);
If you use inherited widget you don't have to worry about watching for the pop of the page you pushed, which will work for basic use-cases but may end up having problems in a more complex scenario.
Short answer:
Use this in 1st page:
Navigator.pushNamed(context, '/page2').then((_) => setState(() {}));
and this in 2nd page:
Navigator.pop(context);
There are 2 things, passing data from
1st Page to 2nd
Use this in 1st page
// sending "Foo" from 1st
Navigator.push(context, MaterialPageRoute(builder: (_) => Page2("Foo")));
Use this in 2nd page.
class Page2 extends StatelessWidget {
final String string;
Page2(this.string); // receiving "Foo" in 2nd
...
}
2nd Page to 1st
Use this in 2nd page
// sending "Bar" from 2nd
Navigator.pop(context, "Bar");
Use this in 1st page, it is the same which was used earlier but with little modification.
// receiving "Bar" in 1st
String received = await Navigator.push(context, MaterialPageRoute(builder: (_) => Page2("Foo")));
For me this seems to work:
Navigator.of(context).pushNamed("/myRoute").then((value) => setState(() {}));
Then simply call Navigator.pop() in the child.
The Easy Trick is to use the Navigator.pushReplacement method
Page 1
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Page2(),
),
);
Page 2
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Page1(),
),
);
Simply add .then((value) { setState(() {}); after Navigator.push on page1() just like below:
Navigator.push(context,MaterialPageRoute(builder: (context) => Page2())).then((value) { setState(() {});
Now when you use Navigator.pop(context) from page2 your page1 rebuild itself
You can use pushReplacement and specify the new Route
onTapFunction(BuildContext context) async {
final reLoadPage = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => IdDetailsScreen()),
);
if (reLoadPage) {
setState(() {});
}
}
Now while doing Navigator.pop from second page to come back to first page just return some value which in my case is of bool type
onTap: () {
Navigator.pop(context, true);
}
my solution went by adding a function parameter on SecondPage, then received the reloading function which is being done from FirstPage, then executed the function before the Navigator.pop(context) line.
FirstPage
refresh() {
setState(() {
//all the reload processes
});
}
then on pushing to the next page...
Navigator.push(context, new MaterialPageRoute(builder: (context) => new SecondPage(refresh)),);
SecondPage
final Function refresh;
SecondPage(this.refresh); //constructor
then on before the navigator pop line,
widget.refresh(); // just refresh() if its statelesswidget
Navigator.pop(context);
Everything that needs to be reloaded from the previous page should be updated after the pop.
This work really good, i got from this doc from flutter page: flutter doc
I defined the method to control navigation from first page.
_navigateAndDisplaySelection(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddDirectionPage()),
);
//below you can get your result and update the view with setState
//changing the value if you want, i just wanted know if i have to
//update, and if is true, reload state
if (result) {
setState(() {});
}
}
So, i call it in a action method from a inkwell, but can be called also from a button:
onTap: () {
_navigateAndDisplaySelection(context);
},
And finally in the second page, to return something (i returned a bool, you can return whatever you want):
onTap: () {
Navigator.pop(context, true);
}
Put this where you're pushing to second screen (inside an async function)
Function f;
f= await Navigator.pushNamed(context, 'ScreenName');
f();
Put this where you are popping
Navigator.pop(context, () {
setState(() {});
});
The setState is called inside the pop closure to update the data.
I had a similar issue.
Please try this out:
In the First Page:
Navigator.push( context, MaterialPageRoute( builder: (context) => SecondPage()), ).then((value) => setState(() {}));
After you pop back from SecondPage() to FirstPage() the "then" statement will run and refresh the page.
You can pass back a dynamic result when you are popping the context and then call the setState((){}) when the value is true otherwise just leave the state as it is.
I have pasted some code snippets for your reference.
handleClear() async {
try {
var delete = await deleteLoanWarning(
context,
'Clear Notifications?',
'Are you sure you want to clear notifications. This action cannot be undone',
);
if (delete.toString() == 'true') {
//call setState here to rebuild your state.
}
} catch (error) {
print('error clearing notifications' + error.toString());
}
}
Future<bool> deleteLoanWarning(BuildContext context, String title, String msg) async {
return await showDialog<bool>(
context: context,
child: new AlertDialog(
title: new Text(
title,
style: new TextStyle(fontWeight: fontWeight, color: CustomColors.continueButton),
textAlign: TextAlign.center,
),
content: new Text(
msg,
textAlign: TextAlign.justify,
),
actions: <Widget>[
new Container(
decoration: boxDecoration(),
child: new MaterialButton(
child: new Text('NO',),
onPressed: () {
Navigator.of(context).pop(false);
},
),
),
new Container(
decoration: boxDecoration(),
child: new MaterialButton(
child: new Text('YES', ),
onPressed: () {
Navigator.of(context).pop(true);
},
),
),
],
),
) ??
false;
}
Regards,
Mahi
In flutter 2.5.2 this is worked for me also it works for updating a list
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage()))
.then((value) => setState(() {}));
then in the second page I just code this
Navigator.pop(context);
I have a ListView in fist page which is display a list[] data, the second page was updating the data for my list[] so the above code works for me.
Needed to force rebuild of one of my stateless widgets. Did't want to use stateful. Came up with this solution:
await Navigator.of(context).pushNamed(...);
ModalRoute.of(enclosingWidgetContext);
Note that context and enclosingWidgetContext could be the same or different contexts. If, for example, you push from inside StreamBuilder, they would be different.
We don't do anything here with ModalRoute. The act of subscribing alone is enough to force rebuild.
If you are using an alert dialog then you can use a Future that completes when the dialog is dismissed. After the completion of the future you can force widget to reload the state.
First page
onPressed: () async {
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
....
);
}
);
setState(() {});
}
In Alert dialog
Navigator.of(context).pop();
This simple code worked for me to go to the root and reload the state:
...
onPressed: () {
Navigator.of(context).pushNamedAndRemoveUntil('/', ModalRoute.withName('/'));
},
...
In short, you should make the widget watch the state. You need state management for this.
My method is based on Provider explained in Flutter Architecture Samples as well as Flutter Docs. Please refer to them for more concise explanation but more or less the steps are :
Define your state model with states that the widget needs to observe.
You could have multiple states say data and isLoading, to wait for some API process. The model itself extends ChangeNotifier.
Wrap the widgets that depend on those states with watcher class.
This could be Consumer or Selector.
When you need to "reload", you basically update those states and broadcast the changes.
For state model the class would look more or less as follows. Pay attention to notifyListeners which broadcasts the changes.
class DataState extends ChangeNotifier{
bool isLoading;
Data data;
Future loadData(){
isLoading = true;
notifyListeners();
service.get().then((newData){
isLoading = false;
data = newData;
notifyListeners();
});
}
}
Now for the widget. This is going to be very much a skeleton code.
return ChangeNotifierProvider(
create: (_) => DataState()..loadData(),
child: ...{
Selector<DataState, bool>(
selector: (context, model) => model.isLoading,
builder: (context, isLoading, _) {
if (isLoading) {
return ProgressBar;
}
return Container(
child: Consumer<DataState>(builder: (context, dataState, child) {
return WidgetData(...);
}
));
},
),
}
);
Instance of the state model is provided by ChangeNotifierProvider. Selector and Consumer watch the states, each for isLoading and data respectively. There is not much difference between them but personally how you use them would depend on what their builders provide. Consumer provides access to the state model so calling loadData is simpler for any widgets directly underneath it.
If not then you can use Provider.of. If we'd like to refresh the page upon return from the second screen then we can do something like this:
await Navigator.push(context,
MaterialPageRoute(
builder: (_) {
return Screen2();
));
Provider.of<DataState>(context, listen: false).loadData();
For me worked:
...
onPressed: (){pushUpdate('/somePageName');}
...
pushUpdate (string pageName) async { //in the same class
await pushPage(context, pageName);
setState(() {});
}
//---------------------------------------------
//general sub
pushPage (context, namePage) async {
await Navigator.pushNamed(context, namePage);
}
In this case doesn't matter how you pop (with button in UI or "back" in android) the update will be done.
Very simply use "then" after you push, when navigator pops back it will fire setState and the view will refresh.
Navigator.push(blabla...).then((value) => setState(() {}))
// Push to second screen
await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => SecondScreen(),
),
);
// Call build method to update any changes
setState(() {});
Use setstate in your navigation push code.
Navigator.push(context, MaterialPageRoute(builder: (context) => YourPage())).then((value) {
setState(() {
// refresh state
});
});
This simple code goes to the root and reloads the state even without setState:
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => MainPage()), (Route<dynamic> route) => false,); //// this MainPage is your page to refresh