How to display a card on tapping a FAB? - flutter

So this is what I got so far. Basically, I want to display the card once the user taps on the FAB. Now, when I tap on the FAB, there's no response.
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.exit_to_app),
onPressed: () => logoutUser().then((value) =>
Navigator.of(context).pushReplacementNamed('/SignIn')),
)
],
title: Text('TODO'),
),
body: Container(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add), onPressed: () => displayCard()),
);
}
Widget displayCard() {
return Center(
child: Card(
color: Colors.blue,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
leading: Icon(Icons.album),
title: Text('The Enchanted Nightingale'),
subtitle: Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
),
],
),
),
);
}

Right now, you're returning a Widget to your onPressed function, which is a VoidCallBack. It won't do anything with the Widget it receives back from displayCard().
Consider using a Dialog popup. Replace your widget displayCard() with something like the following.
void displayCard(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("The Enchanted Nightingale"),
content: Text("Music by Julie Gable. Lyrics by Sidney Stein."),
actions: <Widget>[
FlatButton(
child: Text("Dismiss"),
onPressed: () {
//remove the dialog popup
Navigator.of(context).pop();
}
)
]
);
}
);
}
Then, update your floatActionButton code to pass context as a parameter
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add), onPressed: () => displayCard(context)),

Related

Display SnackBar on top of AlertDialog widget

I have an AlertDialog widget that will cause a SnackBar to display when you tap on its Text. The SnackBar currently displays behind the AlertDialog barrier, in the background. I want the Snackbar to display on top of the transparent AlertDialog barrier instead. Is the behavior that I'm seeking possible to achieve in Flutter? I have created a brand new Flutter app and included only the relevant code to illustrate the use-case below, as well as a screenshot.
Main.dart Gist
#override
Widget build(BuildContext context) {
WidgetsBinding.instance!.addPostFrameCallback((_) async {
showDialog(
context: context,
builder: (BuildContext dialogContext) => AlertDialog(
content: GestureDetector(
onTap: () {
ScaffoldMessenger.of(dialogContext).showSnackBar(SnackBar(
content: const Text('snack'),
duration: const Duration(seconds: 1),
action: SnackBarAction(
label: 'ACTION',
onPressed: () {},
),
));
},
child: Center(
child: Text('Show SnackBar!'),
),
),
),
);
});
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Invoke "debug painting" (press "p" in the console, choose the
// "Toggle Debug Paint" action from the Flutter Inspector in Android
// Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
// to see the wireframe for each widget.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Update
Thanks to Amy, I realized that tapping on the barrier did not dismiss the dialog. Also, the code was causing to show multiple SnackBars due to the use of nested Scaffolds.
Check out the following model that fixes all issues:
showDialog
|
|
ScaffoldMessenger => "Set a scope to show SnackBars only in the inner Scaffold"
|
--- Builder => "Add a Builder widget to access the Scaffold Messenger"
|
--- Scaffold => "The inner Scaffold that is needed to show SnackBars"
|
--- GestureDetector => "Dismiss the dialog when tapped outside"
|
--- GestureDetector => "Don't dismiss it when tapped inside"
|
--- AlertDialog => "Your dialog"
Here is the implementation:
showDialog(
context: context,
builder: (context) => ScaffoldMessenger(
child: Builder(
builder: (context) => Scaffold(
backgroundColor: Colors.transparent,
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => Navigator.of(context).pop(),
child: GestureDetector(
onTap: () {},
child: AlertDialog(
content: GestureDetector(
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('snack'),
duration: const Duration(seconds: 1),
action: SnackBarAction(
label: 'ACTION',
onPressed: () {},
),
),
);
},
child: Center(
child: Text('Show SnackBar!'),
),
),
),
),
),
),
),
),
);
Old answer
ScaffoldMessenger shows SnackBar in the nearest descendant Scaffold. If you add another Scaffold before AlertDialog, it will use it instead of the root one which is left behind the dialog.
showDialog(
context: context,
builder: (BuildContext dialogContext) => Scaffold(
backgroundColor: Colors.transparent, // Make Scaffold's background transparent
body: AlertDialog(
content: GestureDetector(
onTap: () {
ScaffoldMessenger.of(dialogContext).showSnackBar(SnackBar(
content: const Text('snack'),
duration: const Duration(seconds: 1),
action: SnackBarAction(
label: 'ACTION',
onPressed: () {},
),
));
},
child: Center(
child: Text('Show SnackBar!'),
),
),
),
),
);
Instead of the SnackBar Use another_flushbar, It will Appear Above AlertDialog.
Flushbar(
backgroundColor: Colors.red,
message: S.of(context).choose_date,
duration: Duration(seconds: Constants.TOAST_DURATION),
).show(context);
Result:
The issue here is that showDialog uses the root navigator provided by MaterialApp. So when you show your dialog it is pushed completely over your scaffold. To solve this you need the navigator that is used to be a child of the scaffold that's showing the snackbars. So the following code adds this navigator, sets useRootNavigator to false to use this navigator, and importantly uses a BuildContext under the newly created navigator:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Navigator( //New navigator added here
initialRoute: '/',
onGenerateRoute: (setting) {
return MaterialPageRoute(
builder: (context) => Center(
child: Builder(builder: (context) {
WidgetsBinding.instance!
.addPostFrameCallback((_) async {
showDialog(
context: context,
useRootNavigator: false,//Dialog must not use root navigator
builder: (BuildContext dialogContext) =>
AlertDialog(
content: GestureDetector(
onTap: () {
ScaffoldMessenger.of(dialogContext)
.showSnackBar(SnackBar(
content: const Text('snack'),
duration: const Duration(seconds: 1),
action: SnackBarAction(
label: 'ACTION',
onPressed: () {},
),
));
},
child: Center(
child: Text('Show SnackBar!'),
),
),
),
);
});
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
]);
}),
));
}),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Result:
Note that this solution does constrain the dialog size a bit and the app bar and floating action button is above the content, which may be undesirable. This can be solved just by adding another scaffold below the newly created navigator and moving those appbar/FAB properties down as desired. Example with AppBar below the modal:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Navigator(
initialRoute: '/',
onGenerateRoute: (setting) {
return MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Builder(builder: (context) {
WidgetsBinding.instance!
.addPostFrameCallback((_) async {
showDialog(
context: context,
useRootNavigator: false,
builder: (BuildContext dialogContext) =>
AlertDialog(
content: GestureDetector(
onTap: () {
ScaffoldMessenger.of(dialogContext)
.showSnackBar(SnackBar(
content: const Text('snack'),
duration: const Duration(seconds: 1),
action: SnackBarAction(
label: 'ACTION',
onPressed: () {},
),
));
},
child: Center(
child: Text('Show SnackBar!'),
),
),
),
);
});
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
]);
}),
)));
}),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Result:
hope this is what you are looking for
import 'package:flutter/material.dart';
class SnackOverDialog extends StatefulWidget {
SnackOverDialog({Key? key}) : super(key: key);
#override
_SnackOverDialogState createState() => _SnackOverDialogState();
}
class _SnackOverDialogState extends State<SnackOverDialog> {
final GlobalKey<ScaffoldState> _scaffoldkey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
///* show snack
_snackbar(BuildContext context) {
_scaffoldkey.currentState!.showSnackBar(SnackBar(
content: const Text('snack'),
duration: const Duration(seconds: 1),
action: SnackBarAction(
label: 'ACTION',
onPressed: () {},
),
));
}
///* dialog
_dialog(BuildContext context) {
WidgetsBinding.instance!.addPostFrameCallback((_) async {
showDialog(
context: context,
builder: (BuildContext dialogContext) => AlertDialog(
content: Scaffold(
key: _scaffoldkey,
body: GestureDetector(
onTap: () {
_snackbar(dialogContext);
},
child: Center(
child: Text('Show SnackBar!'),
),
),
),
),
);
});
}
return Scaffold(
appBar: AppBar(
title: Text("SNackBarOVerDialog"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _dialog(context),
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Flutter : background is squeezed to the left when keyboard shows up

I have a problem when I want to fill a TextView and the keyboard shows up, the scaffold is squeezing to the left.
Anybody have a clue about that ?
This is my code:
#override
Widget build(BuildContext context) {
final authentCubit = context.watch<AuthentificationCubit>();
final UserRepository user = UserRepository();
print(user.getUserName());
return Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: Column(
children: <Widget>[
ElevatedButton(
child: Text('Deconnexion'),
onPressed: () {
authentCubit.signOut();
},
),
ElevatedButton(
child: Text('Formulaire contact'),
onPressed: () {
showDialog(context: context,builder: (context)=> ContactForm());
},
),
TextField(),
],
),
),
);
}
}
This is a screen of my problem
Thank you
Had two scaffold in my tree, this is why "resizeToAvoidBottomPadding: false," wasn't working.

Why do we need to provide the context in MaterialPageRoute when the build method of the widget is also taking the context?

Why do we need to provide the context in MaterialPageRoute when the build method of the widget is also taking the context?
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}),
);
},

flutter: Can I adjust the width or height of the CupertinoAlertDialog(iOS style)?

I'm new in flutter. I want a iOS style app so I use CupertinoAlertDialog. But I want to customize its height and width. Is that possible? Here is what I have done.
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
body: RaisedButton(
child: Text("Pick Me !!!"),
onPressed: () {
showDialog(
context: context,
builder: (_) => Center(
child: CupertinoAlertDialog (
title: new Text("drop out"),
content: new Text("quit the window"),
actions: <Widget>[
FlatButton(
child: Text('Cancle!'),
onPressed: () {
Navigator.pop(_);
},
),
FlatButton(
child: Text('OK'),
onPressed: () {
Navigator.pop(_);
},
)
],
),
)
);
},
)
),
);
}

Alert Dialog on onTap on ListTile

How can I create a AlertDialog by clicking/tapping on ListTile.
Currently I'm doing this and nothing happens when it's clicked.
body: ListView(
children: <Widget>[
ListTile(
title: Text('Theme'),
onTap: (){
AlertDialog(
title: Text('Hi'),
);
},
)
],
),
PS: I'm a noob, please go easy on me.
you are very close, you created the dialog, just need to show it:
body: ListView(
children: <Widget>[
ListTile(
title: Text('Theme'),
onTap: () {
AlertDialog alert = AlertDialog(
title: Text('Hi'),
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
},
)
],
),
Change your ListTile with this.
ListTile(
title: Text('Theme'),
onTap: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Alert Dialog Example'),
content: Text('Alert Dialog Body Goes Here ..'),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('OK')),
],
);
});
},
)
I have also added some properties to use the AlertDialog(), like title, content and actions