I am trying to do a log in app, after finishing with the design I faced a problem where I could not add the function of going back to the old page, I searched and found about the appBar but I could not apply it.
class Body extends StatelessWidget {
const Body({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Background(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"LOGIN",
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: size.height * 0.03),
SizedBox(height: size.height * 0.03),
RoundedInputField(
hintText: "Your Email",
onChanged: (value) {},
),
RoundedPasswordField(
onChanged: (value) {},
),
RoundedButton(
text: "LOGIN",
press: () {},
),
SizedBox(height: size.height * 0.03),
AlreadyHaveAnAccountCheck(
press: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return SignUpScreen();
},
),
);
},
),
],
),
),
);
}
}
You must use Scaffold Widget for displaying the AppBar try below code hope its helpful to you In Scaffold widget you declare AppBar for Appbar refer ducumentation here :
class AppBarPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Your Title'),
),
body: Container(),
);
}
}
Your Screen look like this->
use Scaffold.
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("MyHomePage"),
actions: [
TextButton(onPressed: (){
Navigator.of(context).pop();
}, child: Icon(Icons.arrow_back))
],
),
body:Body() ,
);
}
}
on onPressed event you can return to old page
appBar can be used inside Scaffold.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AppBar Demo'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back),
tooltip: 'Show Snackbar',
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
body: const Center(
child: Text(
'This is the home page',
style: TextStyle(fontSize: 24),
),
),
);
}
Related
I have 2 page, page1 and page2. page1 navigate to page2. page2 has endDrawer inside scaffold, but i must wrap scaffold with materialApp. When endDrawer open and i call Navigator.of(context).pop() or Navigator.pop(context), it will back to page1 instead close endDrawer. How to close the endDrawer and not back to page1? all i know to close drawer is use pop
I think you are using wrong context:
Check the code below which can complete your task:
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
title: 'Navigation Basics',
home: FirstRoute(),
));
}
class FirstRoute extends StatelessWidget {
const FirstRoute({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('First Route'),
),
body: Center(
child: ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondRoute()),
);
},
),
),
);
}
}
class SecondRoute extends StatelessWidget {
const SecondRoute({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text("Second Route"),
),
endDrawer: Builder(
builder: (context) {
return Container(
width: 100,
color: Colors.black,
alignment: Alignment.center,
child: GestureDetector(
child: const Text(
"close drawer",
style: TextStyle(
color: Colors.white,
),
),
onTap: () {
Navigator.pop(context);
},
),
);
},
),
body: Builder(builder: (context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
child: const Text('open drawer'),
),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Go back!'),
),
],
),
);
}),
),
);
}
}
how do I call the alert dialog from another dart file, when the user clicks the button in addstudents.dart, I want to make the alert dialog in another file just in case it can be reused? In my addstudents.dart i have this Container, please see the code below, thanks.
addstudents.dart
Container(
padding: EdgeInsets.only(top: 10),
width: (globals.screenWidth * 0.48),
height: (globals.screenHeight * 0.10),
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(10)),
child: RaisedButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(10.0),
),
onPressed: () {
// calling another file dart
},
color: Colors.green,
child: RichText(
text: TextSpan(
text: "Confirmed!",
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "Nunito",
color: Colors.white,
fontSize: globals.fontsize_19)),
),
),
),
this is my alertdialog.dart
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Flutter'),
),
body: MyLayout()),
);
}
}
class MyLayout extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: Text('Show alert'),
onPressed: () {
showAlertDialog(context);
},
),
);
}
}
showAlertDialog(BuildContext context) {
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {},
);
AlertDialog alert = AlertDialog(
title: Text("My title"),
content: Text("This is my message."),
actions: [
okButton,
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Dunno if this is the best practice but here's what I'm doing
class Alerts {
static showAlertDialog(BuildContext context) {
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {},
);
AlertDialog alert = AlertDialog(
title: Text("My title"),
content: Text("This is my message."),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
}
I call them using Alerts.showAlertDialog(context);
I am using two widgets(Text and Flatbutton) in Row. Whatever I do, there is space between them. I don't want any space between them how to do that?
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("TextColor checking"),
),
body:
Row(mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Already have a account?"),
FlatButton(
onPressed: () {},
child: Text("Login"),
textColor: Colors.indigo,
),
],
),
),
);
}
}
I want like this: Already have a account? Login
If you want to create a simple text like that, dont use row or flat button. Use Rich text instead.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("TextColor checking"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: RichText(
text: TextSpan(
style: TextStyle(fontSize: 16, color: Colors.white),
children: <TextSpan>[
TextSpan(
text: "Don't have an account? ",
),
TextSpan(
text: "Login",
style: TextStyle(
//Add any decorations here
color: Colors.indigo,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
//Enter the function here
},
),
],
),
),
),
),
);
}
}
You're getting the space because you are using a FlatButton and FlatButtons has padding by default. You should use a GestureDetector instead.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("TextColor checking"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Already have a account? "),
GestureDetector(
onTap: () {},
child: Text(
"Login",
style: TextStyle(
color: Colors.indigo,
),
),
),
],
),
),
),
);
}
}
I tried your code and in seams the space is not between the components, but its is the padding of the FlatButton. to remove that, you will have use another component instead of Flat Button. try the below
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("TextColor checking"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Already have a account?"),
RawMaterialButton(
constraints: BoxConstraints(),
padding: EdgeInsets.all(
5.0), // optional, in order to add additional space around text if needed
child: Text('Login'),
onPressed: () {})
// FlatButton(
// onPressed: () {},
// child: Text("Login"),
// textColor: Colors.indigo,
// ),
],
),
),
),
);
}
}
I am new to flutter.
In my real problem, my client is in places where it is very frequent that the internet is very slow, so sometimes an attempt is made to make a web request and this may take time, so the user leaves the screen before the web request is completed. Sometimes my app after completing a web request generates a dialog. So here is where my problem lies, the user is trying to make a web request and while it is done, they leave the screen and then the dialog is generated.
I am trying to simulate this problem with a delay that later generates the dialog.
I am not thinking of any strategy to end the web request, what I want is to find a way that once I leave the screen, causes the dialog not to be generated something like a dispose
I made an example where I have 2 screens. On the second screen a dialog is generated with a delay of 5 seconds when the button is clicked. If I navigate to another screen before the dialog is opened I get an error. I assume this occurs because the view was destroyed and therefore the dialog cannot be opened.
What can I do to avoid the error when the dialog is generated after being in another view? if I am in another view I DO NOT WANT the dialog to be generated.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
print("main");
return MaterialApp(title: 'Provider Example', initialRoute: '/', routes: {
'/': (context) => Home(),
'home': (context) => Home(),
'dialogpage': (context) => Dialogpage(),
});
}
}
class Home extends StatelessWidget {
Home() {
print("home");
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Text('home'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () {
Navigator.pushNamed(context, "dialogpage");
},
),
],
),
body: const Center(
child: Text(
'home',
style: TextStyle(fontSize: 24),
),
),
);
}
}
class Dialogpage extends StatelessWidget {
Dialogpage() {
print("dialogpage");
}
dialog(BuildContext context) {
Future.delayed(const Duration(seconds: 5), () {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0)),
title: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(19.0),
topRight: Radius.circular(19.0),
),
),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 5),
child: Text(
'Error',
style: TextStyle(color: Colors.white),
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Icon(
Icons.error,
size: 50,
),
),
Text("dialog"),
],
),
titlePadding: EdgeInsets.all(0),
actions: <Widget>[
FlatButton(
child: Text('Aceptar'),
onPressed: () {
return Navigator.of(context).pop();
}),
],
);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('dialog'),
),
body: Center(
child: RaisedButton(
child: Text("show dialog"),
onPressed: () {
dialog(context);
}),
),
);
}
}
use Globalkey in scaffold in then check the context in dialog method is it != null
then run dialog otherwise don't...
GlobalKey _scafolldKey = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scafolldKey,
appBar: AppBar(
title: const Text('dialog'),),
body: Center(
child: RaisedButton(
child: Text("show dialog"),
onPressed: () {
dialog(context);
}),
),
);
}
}
dialog(BuildContext context) {
Future.delayed(const Duration(seconds: 2), () {
if(_scafolldKey.currentContext !=null){
showDialog();
}
});
}
Instead of Future.delayed, you should use Timer, which can be cancelled in onDispose method.
Working solution:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
print("main");
return MaterialApp(
title: 'Provider Example',
initialRoute: '/',
routes: {
'/': (context) => Home(),
'home': (context) => Home(),
'dialogpage': (context) => Dialogpage(),
},
);
}
}
class Home extends StatelessWidget {
Home() {
print("home");
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('home'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () {
Navigator.pushNamed(context, "dialogpage");
},
),
],
),
body: const Center(
child: Text(
'home',
style: TextStyle(fontSize: 24),
),
),
);
}
}
class Dialogpage extends StatefulWidget {
#override
_DialogpageState createState() => _DialogpageState();
}
class _DialogpageState extends State<Dialogpage> {
Timer _timer;
#override
void dispose() {
_timer?.cancel();
super.dispose();
}
dialog(BuildContext context) {
_timer = Timer(
const Duration(seconds: 3),
() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
title: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(19.0),
topRight: Radius.circular(19.0),
),
),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 5),
child: Text(
'Error',
style: TextStyle(color: Colors.white),
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Icon(
Icons.error,
size: 50,
),
),
Text("dialog"),
],
),
titlePadding: EdgeInsets.all(0),
actions: <Widget>[
FlatButton(
child: Text('Aceptar'),
onPressed: () {
return Navigator.of(context).pop();
},
),
],
);
},
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('dialog'),
),
body: Center(
child: RaisedButton(
child: Text("show dialog"),
onPressed: () {
dialog(context);
},
),
),
);
}
}
Try this code
class Dialogpage extends StatelessWidget {
...
Timer t;
dialog(BuildContext context) {
t = Timer(Duration(seconds: 5), () {
showDialog(...);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('dialog'),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () {
t?.cancel();
Navigator.of(context).pop();
},
),
),
body: Center(
child: RaisedButton(
child: Text("show dialog"),
onPressed: () {
dialog(context);
}),
),
);
}
}
Hope it helps.
I want to have the top half of by screen appear static when navigating between pages in Flutter.
To try to make this happen I put use the Hero widget and use it on a column that contains an AppBar and some other content that I want to appear static when pushing a new page.
The App Bar itself remains static but the back arrow disappears when the animation starts and reappears when the animation is done.
How can I have the back arrow remain visible the entire time while the rest of the page is animating into place?
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Hero(
tag: 'top',
child: Column(
children: <Widget>[
AppBar(
title: Text('First'),
backgroundColor: Color.fromARGB(255, 50, 64, 182),
),
Container(
height: 80.0,
)
],
),
),
RaisedButton(
child: Text('Next'),
onPressed: () {
Navigator.pushNamed(context, '/second');
},
),
],
),
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Hero(
tag: 'top',
child: Column(
children: <Widget>[
AppBar(
title: Text('Second'),
),
Container(
height: 80.0,
// color: Colors.green,
),
],
),
),
RaisedButton(
child: Text('Back'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
);
}
}
Things weren't quite set up right in your code. It should go Scaffold/Hero/your content. I've also used this simple fading page route when performing the navigation:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First'),
leading: Icon(null),
backgroundColor: Color.fromARGB(255, 50, 64, 182)),
body: Hero(
tag: 'top',
child: Column(
children: <Widget>[
Container(height: 80.0),
RaisedButton(
child: Text('Next'),
onPressed: () {
Navigator.push(context, MyCustomRoute(builder: (context) {
return SecondScreen();
}));
},
),
],
),
),
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second'),
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () {
Navigator.pop(context);
},),
backgroundColor: Color.fromARGB(255, 50, 64, 182)),
body: Hero(
tag: 'top',
child: Column(
children: <Widget>[
Container(height: 80.0),
RaisedButton(
child: Text('Back'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
),
);
}
}
class MyCustomRoute<T> extends MaterialPageRoute<T> {
MyCustomRoute({ WidgetBuilder builder, RouteSettings settings })
: super(builder: builder, settings: settings);
#override
Widget buildTransitions(BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
if (settings.isInitialRoute)
return child;
// Fades between routes. (If you don't want any animation,
// just return child.)
return new FadeTransition(opacity: animation, child: child);
}
}
You could do automaticallyImplyLeading: false and then do
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(),
),
I have it done this way, by adding automaticallyImplyLeading: true,
Hope this solves your problem!
appBar: AppBar(
automaticallyImplyLeading: true,
),