Refresh page after Navigator popUntil - flutter

I am using popUntil to go back to first route by using this code:
Navigator.of(context).popUntil((route) => route.isFirst);
Now how can I refresh the current first page?

import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
MaterialButton(
child: Text('Second Page'),
onPressed: navigateSecondPage,
),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
void navigateSecondPage() {
Route route = MaterialPageRoute(builder: (context) => SecondPage());
Navigator.push(context, route).then(onGoBack);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Center(
child: MaterialButton(
onPressed: () {
Navigator.of(context).popUntil((route) => route.isFirst);
},
child: Text('Go Back'),
),
),
);
}
}
Link: https://codepen.io/nitishk72/pen/YzwGELX
As you can see it uses .then() after Navigator.push() to call the onGoBack function.
https://i.stack.imgur.com/3nPSU.gif

Related

How to Refresh State from Navigator Pop in Flutter

I want to refresh the state when calling Navigator Pop / Navigator Pop Until.
While I was doing some research, I finally found this article Flutter: Refresh on Navigator pop or go back. From the code in the article, it can work fine.
But there is a problem when I use the widget tree, for example like the code below:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
Home Page - Parent Class
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
Button Widget - Widget Class
class ButtonWidget extends StatelessWidget{
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage())).then(onGoBack);
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
SecondPage
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);
},
child: Text('Go Back'),
),
),
);
}
}
Or is there another solution to refresh the state class when calling Navigator Pop / Navigator Pop Until?
re-write your Button's class like this:
class ButtonWidget extends StatelessWidget{
final Function onGoBack;
ButtonWidget({this.onGoBack})
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage())).then(onGoBack);
//to avoid any np exception you can do this: .then(onGoBack ?? () => {})
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
And add the onGoBack function as a parameter from the home page like this:
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(onGoBack: onGoBack),
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
you must sent function on widget
class ButtonWidget extends StatelessWidget{
final Function(dynamic)? refresh;
const ButtonWidget({this.refresh})
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: ()async {
await Navigator.push(context, MaterialPageRoute(builder: (context) =>
SecondPage()));
if(refresh!=null){
refresh!("your params");
}
// The Problem is Here
// How to call a Method onGoBack from HomePage Class
}
);
}
}
and you can use widget
ButtonWidget(
refresh:onGoBack
)
Try this, it just you are calling method out of scope
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refresh on Go Back',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int id = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Data: $id',
style: Theme.of(context).textTheme.headline5,
),
ButtonWidget(
refresh: onGoBack,
)
],
),
),
);
}
void refreshData() {
id++;
}
onGoBack(dynamic value) {
refreshData();
setState(() {});
}
}
class ButtonWidget extends StatelessWidget {
final Function(dynamic)? refresh;
ButtonWidget({Key? key, this.refresh}) : super(key: key);
#override
Widget build(BuildContext context) {
print(refresh);
return RaisedButton(onPressed: () async {
await Navigator.push(
context, MaterialPageRoute(builder: (context) => SecondPage()))
.then((value) => refresh!("okay"));
});
}
}
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);
},
child: Text('Go Back'),
),
),
);
}
}

how to keep bottom navigation bar in all pages with stateful widget in Flutter

I am able to navigate to multiple different pages with visible bottom navigation bar on all pages but not able to switch between all of them so how can I switch between tabs with bottom bar being there in all pages
I got till here using this Answer but not able to make it work i.e to switch between bottom navigation tabs...
in short I want to add view for my message tab i.e second tab and move to it also without losing my bottom navigation bar for every page i navigate to...
so far my code,
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.orange,
items: [
BottomNavigationBarItem(icon: Icon(Icons.call), label: 'Call'),
BottomNavigationBarItem(icon: Icon(Icons.message), label: 'Message'),
],
),
body: Navigator(
onGenerateRoute: (settings) {
Widget page = Page1();
if (settings.name == 'page2') page = Page2();
return MaterialPageRoute(builder: (_) => page);
},
),
);
}
}
// 1st Page:
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Page1')),
body: Center(
child: RaisedButton(
onPressed: () => Navigator.pushNamed(context, 'page2'),
child: Text('Go to Page2'),
),
),
);
}
}
// 2nd Page:
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) => Scaffold(appBar: AppBar(title: Text('Page2')));
}
Try like this:
class HomePage extends StatefulWidget {
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int activeIndex = 0;
void changeActivePage(int index) {
setState(() {
activeIndex = index;
});
}
List<Widget> pages = [];
#override
void initState() {
pages = [
Page1(() => changeActivePage(2)),
Page2(),
Page3(),
];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: SizedBox(
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(onPressed: () => changeActivePage(0), icon: Icon(Icons.call)),
IconButton(onPressed: () => changeActivePage(1), icon: Icon(Icons.message)),
],
),
),
body: pages[activeIndex]);
}
}
// 1st Page:
class Page1 extends StatelessWidget {
final Function callback;
const Page1(this.callback);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Page1')),
body: Center(
child: RaisedButton(
onPressed: () => callback(),
child: Text('Go to Page3'),
),
),
);
}
}
// 2nd Page:
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) =>
Scaffold(appBar: AppBar(title: Text('Page2')));
}
// 3rd Page:
class Page3 extends StatelessWidget {
const Page3();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Page3')),
body: Center(child: Text('Page3')),
);
}
}

How to intercept flutter back-button when keyboard is shown

I want to intercept the back-button of the soft keyboard in flutter. So when I want to close the keyboard by pressing the back-button I want an additional function to be called.
How can I do that?
Keyboard Back button
you can use the keyboard_visibility package to achieve this.
Working Example
the following code displays a SnackBar once the keyboard is dismissed.
import 'package:flutter/material.dart';
import 'package:keyboard_visibility/keyboard_visibility.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
GlobalKey<ScaffoldState> _key;
#override
void initState() {
super.initState();
_key = GlobalKey<ScaffoldState>();
KeyboardVisibilityNotification().addNewListener(
onHide: () {
_key.currentState.showSnackBar(
SnackBar(
content: Text("Keyboard closed"),
),
);
},
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _key,
body: Center(
child: TextField(),
),
),
);
}
}
you can use the https://pub.dev/packages/flutter_keyboard_visibility package to achieve this.
import 'package:flutter/material.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:flutter_keyboard_visibility_example/keyboard_dismiss_demo.dart';
import 'package:flutter_keyboard_visibility_example/provider_demo.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Demo(),
);
}
}
class Demo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return KeyboardDismissOnTap(
child: Scaffold(
appBar: AppBar(
title: Text('Keyboard Visibility Example'),
),
body: Center(
child: Padding(
padding: EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProviderDemo()),
);
},
child: Text('Provider Demo'),
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => KeyboardDismissDemo()),
);
},
child: Text('KeyboardDismiss Demo'),
),
Spacer(),
TextField(
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Input box for keyboard test',
),
),
Container(height: 60.0),
KeyboardVisibilityBuilder(builder: (context, visible) {
return Text(
'The keyboard is: ${visible ? 'VISIBLE' : 'NOT VISIBLE'}',
);
}),
Spacer(),
],
),
),
),
),
);
}
}

How to remove the second appbar in Flutter

I am trying to build a demo chat app with Flutter. After my main screen, I am using Navigator.push to go to the details screen.
Screenshot of problem:
build method of 1st screen:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Chat Thread App"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () {
Navigator.pushNamed(context, '/settings');
},
)
],
),
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: new ChatThreadListCard(messageThreads: _messageThreadLists, user: _user,),
);
}
code of Navigator.push method:
Navigator.push(context, MaterialPageRoute(
builder: (context) => ChatDetailsScreen(threadModel: new ThreadModel(
user.id,
user.fullName,
user.pic,
"otherId",
"otherName",
"otherPic",
post.threadId
)
),
),);
build method of 2nd screen, where the problem is produced:
return Scaffold(
appBar: AppBar(
title: Text("Chat demo"),
),
body: WillPopScope(
child: isLoading
? Center(
child: CircularProgressIndicator(),
)
: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
SizedBox(
width: 300,
height: 300,
),
Column(
children: <Widget>[
buildChat(),
buildInput(),
],
)
],
),
onWillPop: onBackPress,
),
);
the problem turns out to be, i was creating a MaterialApp widget in scaffold's body. so, when the onTap method was called, the new screen was replaced insdie the MaterialApp's area. didnt replace the whole screen.
the trick was to remove the return new MaterialApp().
thanks everyone.
I'm guessing something isn't working right with where you're setting up the Material App?
app.dart:
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage());
}
}
home_page and second_page
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
State createState() => HomePageState();
}
class HomePageState extends State<HomePage> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Page'),
),
body: Container(
child: Center(child: RaisedButton(child: Text('Forward'), onPressed: () async {
await Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage()));
},)),
));
}
}
class SecondPage extends StatefulWidget {
#override
State createState() => SecondPageState();
}
class SecondPageState extends State<SecondPage> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Container(
child: Center(child: RaisedButton(child: Text('Backward'), onPressed: () {
Navigator.of(context).pop();
},)),
));
}
}
Which produces:

Flutter app back button event not redirecting to back page

I am developing a flutter android app. It have three screens. Page 1, Page 2, Page 3. When i entering Page 3 from Page 2. if i click phone back button it want to got to page 2.
But it is redirecting to page 1. I tried after got the reference from
catch Android back button event on Flutter
I tried WillPopScope . It is not entering in onWillPop .
How to solve the problem. My code is shown below.
page 1
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(),
body: MyAppPage()
),
);
}
}
class MyAppPage extends StatefulWidget{
MyAppPage({Key key,}):super(key:key);
#override
_MyAppPageState createState()=> new _MyAppPageState();
}
class _MyAppPageState extends State<MyAppPage>{
#override
Widget build(BuildContext context){
return new Scaffold(
body:RaisedButton(onPressed:(){ Navigator.push(context, MaterialPageRoute(builder: (context) => SecondScreen()));},
child: new Text("got to page 1"),)
);
}
}
page 2
class SecondScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(),
body: SecondPage()
),
);
}
}
class SecondPage extends StatefulWidget{
SecondPage({Key key,}):super(key:key);
#override
SecondPageState createState()=> new SecondPageState();
}
class SecondPageState extends State<SecondPage>{
#override
Widget build(BuildContext context){
return new Scaffold(
body:Column(
children: <Widget>[
new Center(
child: new Text("Page 2"),
),
RaisedButton(onPressed:(){ Navigator.push(context, MaterialPageRoute(builder: (context) => ThirdScreen()));},
child: new Text("go to third Page 3"),)
],
)
);
}
}
page 3
class ThirdScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: new AppBar(),
body: ThirdPage()
),
);
}
}
class ThirdPage extends StatefulWidget{
ThirdPage({Key key,}):super(key:key);
#override
ThirdPageState createState()=> new ThirdPageState();
}
class ThirdPageState extends State<ThirdPage>{
#override
Widget build(BuildContext context){
return new WillPopScope(
child: new Scaffold(
body: new Center(
child: new Text('PAGE 3'),
),
),
onWillPop: (){
debugPrint("onWillPop");
return new Future(() => false);
},
);
}
}
You kinda got confused with the Screen and Pages you created. You actually have more Widgets than you need.
This is what you probably want to do.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(home: MyAppPage());
}
}
class MyAppPage extends StatefulWidget {
#override
_MyAppPageState createState() => _MyAppPageState();
}
class _MyAppPageState extends State<MyAppPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 1")),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Center(child: Text("got to page 1")),
RaisedButton(
child: Text("Go to Page 2"),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage()));
},
),
],
),
);
}
}
class SecondPage extends StatefulWidget {
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 2")),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Center(
child: Text("I'm in Page 2"),
),
RaisedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => ThirdPage()));
},
child: Text("go to third Page 3"),
)
],
)
);
}
}
class ThirdPage extends StatefulWidget {
#override
_ThirdPageState createState() => _ThirdPageState();
}
class _ThirdPageState extends State<ThirdPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Page 3")),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Center(child: Text('PAGE 3')),
RaisedButton(
child: Text("aditional back button"),
onPressed: () => Navigator.of(context).pop(),
),
],
),
);
}
}
On your 3rd page, try to use
onWillPop: () {
Navigator.of(context).pop();
},
for my case, I should upgrade the flutter master branch to the latest code.
flutter channel master
flutter upgrade --force
flutter doctor -v