Related
I am using Flutter + the camera package to create a photo and show it in a preview.
Inside the preview the user can decide if he wants to keep / use this photo - or if he wants to repeat that shot.
Problem:
When repeating the photo, the Preview-Page shows the same image as in the first try.
When using the image (sending it to an API) the user will be redirected to the page that initiated the camera call. But even there - when doing it again, the old preview is visible.
Initiating Page (Let's call it "StartPage")
SizedBox(
width: double.infinity,
child: IconButton(
icon: const Icon(Icons.camera_alt_outlined),
iconSize: 80,
color: Colors.grey,
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PhotoPage()))
.then((value) => setState(() {}));
},
),
)
The PhotoPage shows the live camera image (Everything works fine and API call works)
class PhotoPage extends StatefulWidget {
#override
_PhotoPageState createState() => _PhotoPageState();
}
class _PhotoPageState extends State<PhotoPage> {
CameraController? cameraController;
List? cameras;
int? selectedCameraIndex;
String? imgPath;
Future initCamera(CameraDescription cameraDescription) async {
if (cameraController != null) {
await cameraController!.dispose();
}
cameraController =
CameraController(cameraDescription, ResolutionPreset.veryHigh);
cameraController!.addListener(() {
if (mounted) {
setState(() {});
}
});
if (cameraController!.value.hasError) {
print('Camera Error ${cameraController!.value.errorDescription}');
}
try {
await cameraController!.initialize();
} catch (e) {
showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
Widget cameraPreview() {
if (cameraController == null || !cameraController!.value.isInitialized) {
return Text(
'Loading',
style: TextStyle(
color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold),
);
}
return AspectRatio(
aspectRatio: cameraController!.value.aspectRatio,
child: CameraPreview(cameraController!),
);
}
Widget cameraControl(context) {
return Stack(
children: <Widget>[
Align(
alignment: Alignment.centerRight,
child: FloatingActionButton.extended(
icon: Icon(Icons.camera),
label: Text(''),
backgroundColor: Colors.green,
onPressed: () {
onCapture(context);
}))
],
//),
);
}
onCapture(context) async {
try {
var p = await getTemporaryDirectory();
var name = 'test';
var path = "${p.path}/$name.png";
XFile image = await cameraController!.takePicture();
image.saveTo(path);
await cameraController!.takePicture().then((value) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreviewScreen(
imgPath: path,
fileName: "$name.png",
key: UniqueKey(),
))).then((value) => setState(() {}));
});
} catch (e) {
showCameraException(e);
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
]);
availableCameras().then((value) {
cameras = value;
if (cameras!.length > 0) {
setState(() {
selectedCameraIndex = 0;
});
initCamera(cameras![selectedCameraIndex!]).then((value) {});
} else {
print('No camera available');
}
}).catchError((e) {
print('Error : ${e.code}');
});
}
#override
dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
]);
imgPath = '';
cameraController!.dispose();
PaintingBinding.instance!.imageCache!.clear();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Stack(children: <Widget>[
CameraPreview(cameraController!),
Align(
alignment: Alignment.bottomCenter,
child: Image(
image: new AssetImage(
"assets/layer.png",
),
)),
Align(
alignment: Alignment.bottomCenter,
child: Text(
"Please hold the phone in Landscape mode",
textAlign: TextAlign.center,
textScaleFactor: 1.3,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
).tr(),
),
cameraControl(context),
]),
);
}
showCameraException(e) {
String errorText = 'Error ${e.code} \nError message: ${e.description}';
}
}
So I am pushing the path of the Image to the PreviewScreen:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PreviewScreen(
imgPath: path,
fileName: "$name.png",
key: UniqueKey(),
))).then((value) => setState(() {}));
});
My PreviewScreen looks as follows:
class PreviewScreen extends StatefulWidget {
String? imgPath;
String? fileName;
PreviewScreen(
{required this.imgPath, required this.fileName, required Key key})
: super(key: key);
#override
_PreviewScreenState createState() => _PreviewScreenState();
}
final SaveController controller = Get.put(SaveController());
class _PreviewScreenState extends State<PreviewScreen> {
/* #override
void initState() {
super.initState();
} */
#override
void dispose() {
SaveController().dispose();
_PreviewScreenState().dispose();
PaintingBinding.instance!.imageCache!.clear();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
//child: Stack(
//crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(children: [
Expanded(
flex: 2,
child: Image.file(
File(widget.imgPath!),
fit: BoxFit.cover,
),
)
]),
Align(
alignment: Alignment.bottomLeft,
child: FloatingActionButton.extended(
icon: Icon(Icons.repeat_outlined),
label: Text('Repeat').tr(),
backgroundColor: Colors.red,
onPressed: () {
widget.imgPath = '';
setState(() {});
Navigator.pop(context);
}
//Get.back();
),
),
Align(
alignment: Alignment.bottomRight,
child: FloatingActionButton.extended(
icon: Icon(Icons.check_circle_outline_sharp),
label: Text('Confirm').tr(),
backgroundColor: Colors.green,
onPressed: () {
SystemServices.savePhoto(widget.imgPath!)
.then((value) => setState(() {}));
},
),
),
],
),
);
}
Future getBytes() async {
Uint8List bytes = File(widget.imgPath!).readAsBytesSync();
// print(ByteData.view(buffer))
return ByteData.view(bytes.buffer);
}
}
The "Repeat"-Function looks as follows:
onPressed: () {
widget.imgPath = '';
setState(() {});
Navigator.pop(context);
}
Unfortunately, I really have no clue anymore.
As far as I can see it (I am a beginner in Flutter), the state is cleared and variables are empty.
Can someone tell me, why the photo in the PreviewScreen remains the same? What am I doing wrong?
Thank you very much, I really appreciate any kind of tip.
It seems like, this is the solution to for that problem:
#override
void initState() {
imageCache!.clear();
imageCache!.clearLiveImages();
super.initState();
}
i want to navigate to new screen on click icons of BottomAppBar but i get an error :
only static members can be accessed in initializers
final makeBottom = Container(
height: 45.0,
child: BottomAppBar(
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(Icons.home, color: Color.fromARGB(255, 30, 110, 160)),
onPressed: navigateToPage,//only static members can be accessed in initializers
),
IconButton(
icon: Icon(Icons.search, color: Color.fromARGB(255, 30, 110, 160)),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.star, color: Color.fromARGB(255, 30, 110, 160)),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.favorite_border,
color: Color.fromARGB(255, 30, 110, 160)),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.account_circle,
color: Color.fromARGB(255, 30, 110, 160)),
onPressed: () {},
),
],
),
),
);
the method navigateToPage
void navigateToPage() async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Userqst(
user: widget.user,
),
fullscreenDialog: true));
}
Try this below code..
return Scaffold{
bottomNavigationBar : bottomNav() // call the Widget
}
Widget bottomNav(){
return new Container (
height :45.0,
//Copy the bottomAppBar code
);
}
Problem can be your method can't get context
So at your Iconbutton pass context like this
IconButton(
icon: Icon(Icons.home, color: Color.fromARGB(255, 30, 110, 160)),
onPressed: (){navigateToPage(context);},//only static members can be accessed in initializers
),
And try modifying method like this
void navigateToPage(BuildContext context) async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Userqst(
user: widget.user,
),
fullscreenDialog: true));
}
I think you're trying to build that Widget out of the "Widget build(BuildContext context)" context, that's why you're having this problem.
I thought about 2 solutions for that.
First, you place your code into the main function "Widget build(BuildContext context)" and call the Widget wherever you want to.
#override
Widget build(BuildContext context){
//here you put your "final makeBottom" code;
return Scaffold(//and somewhere around there you place your "makeBottom" Widget);
}
Second, wrap your whole code as a Function which will return that Container() and then call it into the "build" function.
Widget makeBottom(BuildContext context){
return //your Container();
}
Below code may help you -
class Home extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _HomeState();
}
}
class _HomeState extends State<Home> {
int _currentIndex = 0;
final List<Widget> _children = [
HomeListView(),
MyGridView()
];
var _title = 'Home';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color.fromRGBO(41, 167, 77, 50),
title: Text(_title, textAlign: TextAlign.center),
),
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
selectedItemColor: Color.fromRGBO(33, 137, 38, 60),
type: BottomNavigationBarType.fixed,
backgroundColor: Color.fromRGBO(252, 207, 3, 60),
currentIndex: _currentIndex,
// this will be set when a new tab is tapped
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text('Home'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.mail),
title: new Text('My Venue'),
)
],
),
);
}
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
switch (index) {
case 0:
_title = 'Home';
break;
case 1:
_title = 'My Venue';
break;
}
});
}
}
I am learning to build apps in Flutter. Now I have come to alert dialogs. I have done them before in Android and iOS, but how do I make an alert in Flutter?
Here are some related SO questions:
How to style AlertDialog Actions in Flutter
adding dropdown menu in alert dialog box in flutter
Show alert dialog on app main screen load automatically
how to refresh alertdialog in flutter
Alert Dialog with Rounded corners in flutter
I'd like to make a more general canonical Q&A so my answer is below.
One Button
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () { },
);
// set up the AlertDialog
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;
},
);
}
Two Buttons
showAlertDialog(BuildContext context) {
// set up the buttons
Widget cancelButton = TextButton(
child: Text("Cancel"),
onPressed: () {},
);
Widget continueButton = TextButton(
child: Text("Continue"),
onPressed: () {},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("AlertDialog"),
content: Text("Would you like to continue learning how to use Flutter alerts?"),
actions: [
cancelButton,
continueButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Three Buttons
showAlertDialog(BuildContext context) {
// set up the buttons
Widget remindButton = TextButton(
child: Text("Remind me later"),
onPressed: () {},
);
Widget cancelButton = TextButton(
child: Text("Cancel"),
onPressed: () {},
);
Widget launchButton = TextButton(
child: Text("Launch missile"),
onPressed: () {},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("Notice"),
content: Text("Launching this missile will destroy the entire universe. Is this what you intended to do?"),
actions: [
remindButton,
cancelButton,
launchButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Handling button presses
The onPressed callback for the buttons in the examples above were empty, but you could add something like this:
Widget launchButton = TextButton(
child: Text("Launch missile"),
onPressed: () {
Navigator.of(context).pop(); // dismiss dialog
launchMissile();
},
);
If you make the callback null, then the button will be disabled.
onPressed: null,
Supplemental code
Here is the code for main.dart in case you weren't getting the functions above to run.
import 'package:flutter/material.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: ElevatedButton(
child: Text('Show alert'),
onPressed: () {
showAlertDialog(context);
},
),
);
}
}
// replace this function with the examples above
showAlertDialog(BuildContext context) { ... }
I used similar approach, but I wanted to
Keep the Dialog code as a widget in a separated file so I can reuse it.
Blurr the background when the dialog is shown.
Code:
1. alertDialog_widget.dart
import 'dart:ui';
import 'package:flutter/material.dart';
class BlurryDialog extends StatelessWidget {
String title;
String content;
VoidCallback continueCallBack;
BlurryDialog(this.title, this.content, this.continueCallBack);
TextStyle textStyle = TextStyle (color: Colors.black);
#override
Widget build(BuildContext context) {
return BackdropFilter(
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
child: AlertDialog(
title: new Text(title,style: textStyle,),
content: new Text(content, style: textStyle,),
actions: <Widget>[
new FlatButton(
child: new Text("Continue"),
onPressed: () {
continueCallBack();
},
),
new FlatButton(
child: Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
));
}
}
You can call this in main (or wherever you want) by creating a new method like:
_showDialog(BuildContext context)
{
VoidCallback continueCallBack = () => {
Navigator.of(context).pop(),
// code on continue comes here
};
BlurryDialog alert = BlurryDialog("Abort","Are you sure you want to abort this operation?",continueCallBack);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
You can use this code snippet for creating a two buttoned Alert box,
import 'package:flutter/material.dart';
class BaseAlertDialog extends StatelessWidget {
//When creating please recheck 'context' if there is an error!
Color _color = Color.fromARGB(220, 117, 218 ,255);
String _title;
String _content;
String _yes;
String _no;
Function _yesOnPressed;
Function _noOnPressed;
BaseAlertDialog({String title, String content, Function yesOnPressed, Function noOnPressed, String yes = "Yes", String no = "No"}){
this._title = title;
this._content = content;
this._yesOnPressed = yesOnPressed;
this._noOnPressed = noOnPressed;
this._yes = yes;
this._no = no;
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: new Text(this._title),
content: new Text(this._content),
backgroundColor: this._color,
shape:
RoundedRectangleBorder(borderRadius: new BorderRadius.circular(15)),
actions: <Widget>[
new FlatButton(
child: new Text(this._yes),
textColor: Colors.greenAccent,
onPressed: () {
this._yesOnPressed();
},
),
new FlatButton(
child: Text(this._no),
textColor: Colors.redAccent,
onPressed: () {
this._noOnPressed();
},
),
],
);
}
}
To show the dialog you can have a method that calls it NB after importing BaseAlertDialog class
_confirmRegister() {
var baseDialog = BaseAlertDialog(
title: "Confirm Registration",
content: "I Agree that the information provided is correct",
yesOnPressed: () {},
noOnPressed: () {},
yes: "Agree",
no: "Cancel");
showDialog(context: context, builder: (BuildContext context) => baseDialog);
}
OUTPUT WILL BE LIKE THIS
Here is a shorter, but complete code.
If you need a dialog with only one button:
await showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Message'),
content: Text(
'Your file is saved.'),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.of(context, rootNavigator: true)
.pop(); // dismisses only the dialog and returns nothing
},
child: new Text('OK'),
),
],
),
);
If you need a dialog with Yes/No buttons:
onPressed: () async {
bool result = await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Confirmation'),
content: Text('Do you want to save?'),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.of(context, rootNavigator: true)
.pop(false); // dismisses only the dialog and returns false
},
child: Text('No'),
),
FlatButton(
onPressed: () {
Navigator.of(context, rootNavigator: true)
.pop(true); // dismisses only the dialog and returns true
},
child: Text('Yes'),
),
],
);
},
);
if (result) {
if (missingvalue) {
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text('Missing Value'),
));
} else {
saveObject();
Navigator.of(context).pop(_myObject); // dismisses the entire widget
}
} else {
Navigator.of(context).pop(_myObject); // dismisses the entire widget
}
}
Simply used this custom dialog class which field you not needed to leave it or make it null so this customization you got easily.
import 'package:flutter/material.dart';
class CustomAlertDialog extends StatelessWidget {
final Color bgColor;
final String title;
final String message;
final String positiveBtnText;
final String negativeBtnText;
final Function onPostivePressed;
final Function onNegativePressed;
final double circularBorderRadius;
CustomAlertDialog({
this.title,
this.message,
this.circularBorderRadius = 15.0,
this.bgColor = Colors.white,
this.positiveBtnText,
this.negativeBtnText,
this.onPostivePressed,
this.onNegativePressed,
}) : assert(bgColor != null),
assert(circularBorderRadius != null);
#override
Widget build(BuildContext context) {
return AlertDialog(
title: title != null ? Text(title) : null,
content: message != null ? Text(message) : null,
backgroundColor: bgColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(circularBorderRadius)),
actions: <Widget>[
negativeBtnText != null
? FlatButton(
child: Text(negativeBtnText),
textColor: Theme.of(context).accentColor,
onPressed: () {
Navigator.of(context).pop();
if (onNegativePressed != null) {
onNegativePressed();
}
},
)
: null,
positiveBtnText != null
? FlatButton(
child: Text(positiveBtnText),
textColor: Theme.of(context).accentColor,
onPressed: () {
if (onPostivePressed != null) {
onPostivePressed();
}
},
)
: null,
],
);
}
}
Usage:
var dialog = CustomAlertDialog(
title: "Logout",
message: "Are you sure, do you want to logout?",
onPostivePressed: () {},
positiveBtnText: 'Yes',
negativeBtnText: 'No');
showDialog(
context: context,
builder: (BuildContext context) => dialog);
Output:
Or you can use RFlutter Alert library for that. It is easily customizable and easy-to-use. Its default style includes rounded corners and you can add buttons as much as you want.
Basic Alert:
Alert(context: context, title: "RFLUTTER", desc: "Flutter is awesome.").show();
Alert with Button:
Alert(
context: context,
type: AlertType.error,
title: "RFLUTTER ALERT",
desc: "Flutter is more awesome with RFlutter Alert.",
buttons: [
DialogButton(
child: Text(
"COOL",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () => Navigator.pop(context),
width: 120,
)
],
).show();
You can also define generic alert styles.
*I'm one of developer of RFlutter Alert.
Minumum code for alert dialog
showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text('Title'),
content: Text(
'Content widget',
),
),
);
If you want beautiful and responsive alert dialog then you can use flutter packages like
rflutter alert ,fancy dialog,rich alert,sweet alert dialogs,easy dialog & easy alert
These alerts are good looking and responsive. Among them rflutter alert is the best. currently I am using rflutter alert for my apps.
showAlertDialog(BuildContext context, String message, String heading,
String buttonAcceptTitle, String buttonCancelTitle) {
// set up the buttons
Widget cancelButton = FlatButton(
child: Text(buttonCancelTitle),
onPressed: () {},
);
Widget continueButton = FlatButton(
child: Text(buttonAcceptTitle),
onPressed: () {
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text(heading),
content: Text(message),
actions: [
cancelButton,
continueButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
called like:
showAlertDialog(context, 'Are you sure you want to delete?', "AppName" , "Ok", "Cancel");
Check out Flutter Dropdown Banner to easily alert users of events and prompt action without having to manage the complexity of presenting, delaying, and dismissing the component.
To set it up:
import 'packages:dropdown_banner/dropdown_banner.dart';
...
class MainApp extends StatelessWidget {
...
#override
Widget build(BuildContext context) {
final navigatorKey = GlobalKey<NavigatorState>();
...
return MaterialApp(
...
home: DropdownBanner(
child: Scaffold(...),
navigatorKey: navigatorKey,
),
);
}
}
To use it:
import 'packages:dropdown_banner/dropdown_banner.dart';
...
class SomeClass {
...
void doSomethingThenFail() {
DropdownBanner.showBanner(
text: 'Failed to complete network request',
color: Colors.red,
textStyle: TextStyle(color: Colors.white),
);
}
}
Click here to see an example
Just to add to the great answers - the best package I found is:
adaptive_dialog: ^1.8.0+1
For a one OK button the best thing I found is using showOkAlertDialog
Implementation:
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter/material.dart';
Widget build(BuildContext context) {
return Container(
child: Center(
child: IconButton(
icon: Icon(
Icons.info,
),
onPressed: () => showOkAlertDialog(
context: context,
okLabel: 'OK',
title: 'Title',
message: 'This is the message',
),
)),
);
}
Clean and dismisses when you click 'Ok'.
If you need a dialog so this code for you. just use showDialog() onPress or any inside a function.
void showDialog() {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text("Login Failed!"),
content: const Text(
"Invalid credential !! Please check your email or password",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w400),
),
actions: <Widget>[
TextButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Container(
child: const Text(
"Try again",
style: TextStyle(color: Colors.cyan, fontSize: 17),
),
),
),
],
),
)}
Demo dialog screenshots
hope its helpful๐๐๐
Simple and working solution that I used: Enjoy
// Sample can be used for exit dialog box on apps
showAlertDialog(BuildContext context) {
Widget okButton = TextButton(
child: const Text("Leave now",style: TextStyle(color: Colors.red),),
onPressed: () { SystemNavigator.pop(); },
);
Widget nopeButton = TextButton(
child: const Text("Stay here"),
onPressed: () { Navigator.pop(context); },
);
AlertDialog alert = AlertDialog(
title: const Text("Leave"),
content: const Text("Are you sure you want to leave?"),
actions: [
nopeButton,
okButton,
],
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Another easy option to show Dialog is to use stacked_services package
_dialogService.showDialog(
title: "Title",
description: "Dialog message Tex",
);
});
This code works and demonstrates how to obtain the button value pressed by the user:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatelessWidget(),
),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: () {
// set up the buttons
Widget cancelButton = TextButton(
child: Text("Cancel"),
onPressed: () => Navigator.pop(context, 'Cancel'),
);
Widget continueButton = TextButton(
child: Text("Ok"),
onPressed: () => Navigator.pop(context, 'Ok'),
);
showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('AlertDialog Title'),
content: const Text('AlertDialog description'),
actions: <Widget>[
cancelButton,
continueButton,
],
),
).then((value) => print(value));
},
child: const Text('Show Dialog'),
);
}
}
Pressing on Ok button. then on Cancel button print
`showDialog<String>(
context: context,
builder: (BuildContext context) =>
AlertDialog(
title: const Text(
'Invalid Password',
style: TextStyle(color: Colors.red),
),
content:
const Text('Create Strong Password'),
actions: <Widget>[
Center(
child: TextButton(
style: TextButton.styleFrom(
primary: Colors.white,
backgroundColor: Colors
.red, // Background Color
),
onPressed: () => Navigator.pop(
context, 'Cancel'),
child: const Text('Cancel'),
),
),
],
),
),`
I want to make a full screen dialog box. Dialog box background must be opaque.
Here is an example:
How to make like this in Flutter?
You can use the Navigator to push a semi-transparent ModalRoute:
import 'package:flutter/material.dart';
class TutorialOverlay extends ModalRoute<void> {
#override
Duration get transitionDuration => Duration(milliseconds: 500);
#override
bool get opaque => false;
#override
bool get barrierDismissible => false;
#override
Color get barrierColor => Colors.black.withOpacity(0.5);
#override
String get barrierLabel => null;
#override
bool get maintainState => true;
#override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
// This makes sure that text and other content follows the material style
return Material(
type: MaterialType.transparency,
// make sure that the overlay content is not cut off
child: SafeArea(
child: _buildOverlayContent(context),
),
);
}
Widget _buildOverlayContent(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'This is a nice overlay',
style: TextStyle(color: Colors.white, fontSize: 30.0),
),
RaisedButton(
onPressed: () => Navigator.pop(context),
child: Text('Dismiss'),
)
],
),
);
}
#override
Widget buildTransitions(
BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
// You can add your own animations for the overlay content
return FadeTransition(
opacity: animation,
child: ScaleTransition(
scale: animation,
child: child,
),
);
}
}
// Example application:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Playground',
home: TestPage(),
);
}
}
class TestPage extends StatelessWidget {
void _showOverlay(BuildContext context) {
Navigator.of(context).push(TutorialOverlay());
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Test')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: RaisedButton(
onPressed: () => _showOverlay(context),
child: Text('Show Overlay'),
),
),
),
);
}
}
Well here is my implementation which is quite straightforward.
from first screen
Navigator.of(context).push(PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) =>
RedeemConfirmationScreen()));
at 2nd screen
class RedeemConfirmationScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.85), // this is the main reason of transparency at next screen. I am ignoring rest implementation but what i have achieved is you can see.
.....
);
}
}
and here are the results.
Screenshot (Flutter's native dialog)
Call this method to show the dialog in fullscreen.
showGeneralDialog(
context: context,
barrierColor: Colors.black12.withOpacity(0.6), // Background color
barrierDismissible: false,
barrierLabel: 'Dialog',
transitionDuration: Duration(milliseconds: 400),
pageBuilder: (_, __, ___) {
return Column(
children: <Widget>[
Expanded(
flex: 5,
child: SizedBox.expand(child: FlutterLogo()),
),
Expanded(
flex: 1,
child: SizedBox.expand(
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Dismiss'),
),
),
),
],
);
},
);
Note: This answer does not discuss making the modal transparent, but is an answer is for the stated question of "How to make a full screen dialog in flutter?". Hopefully this helps other that find this question through a search like I did, that don't need a transparent modal.
Create your modal dialog class:
class SomeDialog extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text('Dialog Magic'),
),
body: new Text("It's a Dialog!"),
);
}
}
In the class that needs to open the dialog, add something like this:
void openDialog() {
Navigator.of(context).push(new MaterialPageRoute<Null>(
builder: (BuildContext context) {
return new SomeDialog();
},
fullscreenDialog: true));
}
If fullscreenDialog above is true, then the app bar will have an "x" close button. If false, it will have a "<-" back arrow.
If you need to get the result of a dialog action, add a button to your dialog that returns a value when popping the navigation stack. Something like this:
onPressed: () {
Navigator
.of(context)
.pop(new MyReturnObject("some value");
}
then in your class opening the dialog, do capture the results with something like this:
void openDialog() async {
MyReturnObject results = await Navigator.of(context).push(new MaterialPageRoute<MyReturnObject>(
builder: (BuildContext context) {
return new SomeDialog();
},
fullscreenDialog: true));
}
You can use showGeneralDialog method with any widget extends from Material like Scaffold, Card, ..etc.
For example I am going to it with Scaffold like this:
showGeneralDialog(
context: context,
pageBuilder: (context, animation, secondaryAnimation) => Scaffold(
backgroundColor: Colors.black87,
body: //Put your screen design here!
),
);
And now you can set your design as a normal screen by using Scaffold.
Note: if you want to go back you can Navigator like this:
Navigator.of(context).pop(null)
Different ways to show fullscreen dialog
A. Material Dialog
showDialog<void>(
context: context,
useSafeArea: false,
builder: (BuildContext context) {
return const SomeScaffoldView();
},
);
B. Cupertino Dialog
showCupertinoDialog<void>(
context: context,
builder: (BuildContext context) {
return const SomeScaffoldView();
},
);
C. Custom Dialog
Flutter uses this under-the-hood when displaying dialogs.
Can customize transition animation with transitionBuilder, here's a random guide with example animations.
showGeneralDialog(
context: context,
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return const SomeScaffoldView();
},
);
Sample Scaffold View used in above snippets.
class SomeScaffoldView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample Fullscreen Dialog'),
),
body: const Center(child: Text('Dialog Body')),
);
}
}
You can use AlertDialog with zero insetPadding like below:
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return StatefulBuilder(builder: (context, setState) {
return AlertDialog(
insetPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))),
content: SizedBox.expand(
child: Column(
children: <Widget>[
SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Wrap(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
flex: 1,
child: Text(
"Sample type",
style: TextStyle(fontWeight: FontWeight.w700),
),
),
Expanded(flex: 1, child: Text(""))
],
),
],
)),
],
),
));
});
},
);
RFlutter Alert is super customizable and easy-to-use alert/popup dialogs for Flutter. You may create reusable alert styles or add buttons as much as you want with ease.
Alert(context: context, title: "RFLUTTER", desc: "Flutter is awesome.").show();
RFlutter
It's easy to use! :)
you can do like this if you use popular flutter library getx
getx link
void showAlertDialogg(
String body,
String? confirmButtonText,
String? cancelButtonText,
Function(bool onConfirm, bool onCancel) clickEvent,
{barrierDismissible = false}) {
Get.dialog(
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextComponent(
body,
textAlign: TextAlign.center,
fontSize: textSmallFontSize,
fontWeight: titleFontWeight,
color: Colors.white,
),
Row(
//crossAxisAlignment : CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: OutlineButtonComponent(
text: cancelButtonText,
borderColor: kPrimaryColor,
onPressed: () {
Get.back();
clickEvent(false, true);
},
textColor: kPrimaryColor,
padding: EdgeInsets.fromLTRB(16, 16, 8, 16),
),
),
Expanded(
flex: 1,
child: ButtonComponent(
text: confirmButtonText,
buttonColor: kPrimaryColor,
onPressed: () {
Get.back();
clickEvent(true, false);
},
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(8, 16,16, 16),
),
),
],
)
],
),
barrierColor: Colors.black12.withOpacity(0.8),
useSafeArea: true
);
}
you can pas params as you want & call this method where you need it. it supports widget so you can setup the widget as you want.
Wrap your top-level widget with Navigator widget like so:
return Navigator(
pages: [
MaterialPage(
child: MainScreen(
child: widgets...
then call showDialog and because useRootNavigator is set to true in default it will use the root navigator that we added above the MainScreen
I am trying to create a transparent full screen dialog on top of activity. I have tried following this thread but solution doesn't work.
In short , what I need is:
full screen dialog.
transparent background except for the widget I use for the dialog
here's my code:
To open dialog
void onNextBtnClick(){
var route = new MaterialPageRoute(
builder: (BuildContext context) =>
new GenreDialogUI(),fullscreenDialog: true
);
Navigator.of(context).push(route);
}
For Dialog view
import 'package:flutter/widgets.dart';
class HolePuncherPainter extends CustomPainter {
static final clearPaint = new Paint()
..color = Colors.transparent,
..blendMode = BlendMode.clear;
const HolePuncherPainter();
#override
void paint(Canvas canvas, Size size) {
canvas.drawRect(
new Rect.fromLTWH(0.0, 0.0, size.width, size.height), clearPaint);
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
class GenreDialogUI extends StatefulWidget {
#override
_GenreDialogUI createState() => new _GenreDialogUI();
}
class _GenreDialogUI extends State<GenreDialogUI> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: addAppbar(),
body: new CustomPaint(
painter: HolePuncherPainter(),
child: new Container(
color: Colors.transparent,
alignment: Alignment.center,
child: UtilCommonWidget.addText('Transparent Dialog', Colors.red, 22.0, 1),
),
),
);
}
}
Navigator.of(context).push(PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) {
return YourFullScreenAlertDialog()
}
));
YourFullScreenAlertDialog could be a widget that has a background color, Colors.transparent, like #creativecreatorormaybenot mentioned earlier.
For me the following worked:
showDialog(
context: context,
builder: (_) => Material(
type: MaterialType.transparency,
child: Center(
// Aligns the container to center
child: Container(
// A simplified version of dialog.
width: 100.0,
height: 56.0,
color: Colors.green,
child: Text('jojo'),
),
),
),
);
Screenshot (showGeneralDialog):
Code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(child: FlutterLogo()),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.open_in_new),
onPressed: () {
showGeneralDialog(
context: context,
barrierColor: Colors.black38,
barrierLabel: 'Label',
barrierDismissible: true,
pageBuilder: (_, __, ___) => Center(
child: Container(
color: Colors.white,
child: Material(
color: Colors.transparent,
child: Text('Dialog', style: TextStyle(color: Colors.black, fontSize: 40),),
),
),
),
);
},
),
);
}
This is my implementation.
From first screen call this.
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (_, __, ___) => const NoInternetScreen(),
opaque: false, ---->> opacity should be false
fullscreenDialog: true));
And in next screen set background color with opacity.
return Scaffold(
backgroundColor: white.withOpacity(0.85),
......
result