AppBar flickers when using Navigator.of(context).pushNamedAndRemoveUntil() - flutter

I'm tying to clear all of the previous routes after the user has logged on to my app. However, I'm having an issue with the following code in my Flutter app:
void clearRoutes()
{
//createLinks();
Navigator.of(context).pushNamedAndRemoveUntil('/my_home', (Route<dynamic> route) => false);
}
Widget build(BuildContext context)
{
WidgetsBinding.instance.addPostFrameCallback((_) => clearRoutes());
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("iWhiz Home"),
),
body: ListView.builder(
itemCount: links.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(links[index]),
);
}
),
);
}
The above code results in this issue:
The line of code that is giving me this issue is Navigator.of(context).pushNamedAndRemoveUntil('/my_home', (Route<dynamic> route) => false);
Can this issue be resolved?

I was able to find a solution. This is the code that was giving me a problem:
class Login extends StatelessWidget
{
void homePage(BuildContext context)
{
Navigator.pushNamed(context, "/my_home");
}
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Login"),
),
body: Center(
child:
Column(
children: [
Text("Welcome to the Login Page"),
ElevatedButton(
onPressed: ()
{
homePage(context);
},
child: Text("Login"),
),
],
)
),
);
}
}
class MyHome extends StatelessWidget
{
void removePreviousRoutes(BuildContext context)
{
//The problem code.
Navigator.of(context).pushNamedAndRemoveUntil('/my_home', (Route<dynamic> route) => false);
}
Widget build(BuildContext context)
{
WidgetsBinding.instance.addPostFrameCallback((_) => removePreviousRoutes(context));
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("My Home"),
),
body: Center(
child:
Text("Welcome to the Home Page"),
)
);
}
}
The initial page that would be displayed is Login. After the user clicks on 'Welcome to the Login Page' they would be directed to the MyHome page. The issue comes from Navigator.of(context).pushNamedAndRemoveUntil('/my_home', (Route<dynamic> route) => false); on the MyHome page.
Solution:
class Login extends StatelessWidget
{
void homePage(BuildContext context)
{
//The solution.
Navigator.pushNamed(context, "/my_home");
Navigator.of(context).pushNamedAndRemoveUntil('/my_home', (Route<dynamic> route) => false);
}
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Login"),
),
body: Center(
child:
Column(
children: [
Text("Welcome to the Login Page"),
ElevatedButton(
onPressed: ()
{
homePage(context);
},
child: Text("Login"),
),
],
)
),
);
}
}
class MyHome extends StatelessWidget
{
Widget build(BuildContext context)
{
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("My Home"),
),
body: Center(
child:
Text("Welcome to the Home Page"),
)
);
}
}
The solution was to push the new route AND remove all previous routes from Login, INSTEAD OF pushing the new route in Login and removing previous routes from Registration. After doing this, I no longer received the flickering issue.

Related

How can i remove previous route if i navigate from drawer in flutter

When I navigate from drawer to any page and return back the drawer keeps open.
For example:
The drawer contains two-button and if I button one and then back, then second and then back.
Now if I press back button of android it will repeat all activities like in chrome.
Hope you get my point. If you need to know anything else from me. let me know
Hope this helps.
void main() {
runApp(
MaterialApp(
routes: {
"/": (context) => HomePage(),
"/settings": (context) => SettingsPage(),
},
),
);
}
String _currentRoute = "/";
Widget buildDrawer(context) {
return Drawer(
child: SafeArea(
child: Column(
children: <Widget>[
ListTile(
title: Text("Home"),
onTap: () => doRoute(context, '/'),
),
ListTile(
title: Text("Settings"),
onTap: () => doRoute(context, '/settings'),
),
],
),
),
);
}
void doRoute(BuildContext context, String name) {
if (_currentRoute != name)
Navigator.pushReplacementNamed(context, name);
else
Navigator.pop(context);
_currentRoute = name;
}
// Page 1 (HomePage)
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Home")),
body: Container(color: Colors.blue.withOpacity(0.5)),
drawer: buildDrawer(context),
);
}
}
// Page 2 (SettingsPage)
class SettingsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Settings")),
body: Container(color: Colors.orange.withOpacity(0.5)),
drawer: buildDrawer(context),
);
}
}

back page with flutter android back button

What codes should I use to go back to the page with the flutter android back button? I looked inside youtube, especially on Stackoverflow, but I couldn't get any results.
You can use WillPopScope
Here is example code:
class MyPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// This function will handle back button
// When true, it's can back to previous page
// when false, back button will do nothing
return true;
},
child: Scaffold(
appBar: AppBar(
title: const Text('Flutter WillPopScope demo'),
),
body: Center(
child: Text('Hello world')
),
),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new WillPopScope(
child: new Scaffold(
appBar: new AppBar(
title: new Text('Page 2'),
),
body: new Center(
child: new Text('PAGE 2'),
),
),
onWillPop: () async {
return false;
},
);
}
}
Future<T> pushPage<T>(BuildContext context, Widget page) {
return Navigator.of(context)
.push<T>(MaterialPageRoute(builder: (context) => page));
}
Can call the page like:
pushPage(context, Page2());

Refresh listView from PopUntil

Just wonder if I use this code to return PageA from PageD, which function will it get called in PageA?
PageD
Navigator.of(context).popUntil(ModalRoute.withName(PageA.ROUTE));
I would like to make the listView on PageA refreshed once it is back from PageD, but I don't know how to achieve it.
I added a then in PageA, but it is not printing anything.
Navigator.pushNamed(context, PageB.ROUTE).then((onValue) {
print("call from Page4");
_refreshListView();
});
Edit
My project flow is Page A > Page B > Page C > Page D > page A.
All you need to do is return data when you pop PageD and await the data when you push.
This code should help:
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(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/',
routes: {
'/' : (context) => PageA(),
'/go': (context) => PageD()
},
);
}
}
class PageA extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page A"),
),
body: Center(
child: ListView(
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_navigateAndDisplaySelection(context);
},
child: Icon(Icons.forward),
),
);
}
_navigateAndDisplaySelection(BuildContext context) async {
final result = await Navigator.pushNamed(
context,
'/go'
);
if(result){
print(result);
//call the refresh ListView here
_refreshListView();
}
}
}
class PageD extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page D"),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white,),
onPressed: (){
Navigator.pop(context, true);
},
)
),
body: Center(
child: Text("Press back!!"),
),
);
}
}
As to what you explained in the comments... you have to pass arguments from Page D to A when navigating.
Hope this helps.
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(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/',
routes: {
'/': (context) => PageA(),
'/b': (context) => PageB(),
'/c': (context) => PageC(),
'/d': (context) => PageD()
},
);
}
}
class PageA extends StatelessWidget {
#override
Widget build(BuildContext context) {
final bool shouldRefresh = ModalRoute.of(context).settings.arguments;
if (shouldRefresh != null) {
print(shouldRefresh);
//call the refresh ListView here
_refreshListView();
}
return Scaffold(
appBar: AppBar(
title: Text("Page A"),
),
body: Center(
child: ListView(
children: <Widget>[],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, '/b');
},
child: Icon(Icons.forward),
),
);
}
}
class PageB extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page B"),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.forward),
onPressed: () {
Navigator.pushNamed(context, '/c');
},
),
);
}
}
class PageC extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page C"),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.forward),
onPressed: () {
Navigator.pushNamed(context, '/d');
},
),
);
}
}
class PageD extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Page D"),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: () {
Navigator.pushNamed(context, '/', arguments: true);
},
)),
body: Center(
child: Text("Press back!!"),
),
);
}
}
If you want to go to Page D when you press back in Page A then use this
class PageA extends StatelessWidget {
#override
Widget build(BuildContext context) {
final bool shouldRefresh = ModalRoute.of(context).settings.arguments;
print(shouldRefresh);
return Scaffold(
appBar: AppBar(
title: Text("Page A"),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: () {
Navigator.pushNamed(
context,
'/d',
arguments: true
);
},
),
),
body: Center(
child: ListView(
children: <Widget>[
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, '/b');
},
child: Icon(Icons.forward),
),
);
}
}

Switching pages in flutter

I have a side menu created using a Drawer Widget and I want to navigate between the pages in the side menu. I am using Navigator.push() to do so, but for some reason, the page won't change.
The items appear in the side menu, but when clicked on, the page remains the same. Does anyone know how I am misusing Navigator.push()?
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context){
return MaterialApp(
title: 'Grid App',
home: Scaffold(
appBar: AppBar(
title: Text('Grip App'),
),
body: Center(
child: Text('Hello, this is the start page!'),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Text("Navigation"),
decoration: BoxDecoration(
color: Colors.grey[700]
),
),
ListTile(
title: Text("First Page"),
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => FirstPage()),);
},
),
ListTile(
title: new Text("Second Page"),
onTap: () {
Navigator.push(context,
new MaterialPageRoute(builder: (context) => new SecondPage()),);
},
),
],
),
),
),
);
}
}
class FirstPage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text("First Page"),
),
body: Center(
child: Text("You're on the first page!"),
),
);
}
}
class SecondPage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text("Second Page"),
),
body: Text("This is the second page"),
);
}
}
Just separate the MaterialApp with another screen. Simply you can right click on the Scaffold widget and select Extract Widget. Give the name to your widget and it will extract your code into another stateless widget.
copy paste this code to dartpad and run it
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context){
return MaterialApp(
title: 'Grid App',
home: NewApp(),
);
}
}
class NewApp extends StatelessWidget {
const NewApp({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Grip App'),
),
body: Center(
child: Text('Hello, this is the start page!'),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Text("Navigation"),
decoration: BoxDecoration(
color: Colors.grey[700]
),
),
ListTile(
title: Text("First Page"),
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => FirstPage()),);
},
),
ListTile(
title: new Text("Second Page"),
onTap: () {
Navigator.push(context,
new MaterialPageRoute(builder: (context) => new SecondPage()),);
},
),
],
),
),
);
}
}
class FirstPage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text("First Page"),
),
body: Center(
child: Text("You're on the first page!"),
),
);
}
}
class SecondPage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text("Second Page"),
),
body: Text("This is the second page"),
);
}
}
The Navigator won't work if you're doing in under the MateriaApp context like you are using. Remove MaterialApp widget to main() or make another Widget for That.
Try this :
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text('Grip App'),
),
body: Center(
child: Text('Hello, this is the start page!'),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Text("Navigation"),
decoration: BoxDecoration(
color: Colors.grey[700]
),
),
ListTile(
title: Text("First Page"),
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => FirstPage()),);
},
),
ListTile(
title: new Text("Second Page"),
onTap: () {
Navigator.push(context,
new MaterialPageRoute(builder: (context) => new SecondPage()),);
},
),
],
),
),
);
}
}
class FirstPage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text("First Page"),
),
body: Center(
child: Text("You're on the first page!"),
),
);
}
}
class SecondPage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text("Second Page"),
),
body: Text("This is the second page"),
);
}
}
Big problem here is using wrong context.
You can't use App context for Navigator. Take a try with Builder
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Grid App',
home: Builder(
builder: (context) => buildScaffold(context),
),
);
}
Scaffold buildScaffold(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Grip App'),
),
body: Center(
child: Text('Hello, this is the start page!'),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Text("Navigation"),
decoration: BoxDecoration(color: Colors.grey[700]),
),
ListTile(
title: Text("First Page"),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => FirstPage()),
);
},
),
ListTile(
title: new Text("Second Page"),
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new SecondPage()),
);
},
),
],
),
),
);
}
}
Quick Fix
void main() => runApp(MaterialApp(home: MyApp()));
Error You are facing
Your current code gives below error, you can see that in the console too
Error: The following assertion was thrown while handling a gesture:
Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
You can solve this by taking MaterialApp or Builder

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: