Related
I'm trying to display the input value below onto another page that contains radio buttons . my aim is that every time i write or change a value in a textfield it gets updated and displays onto a different page with the radio options . The snippet of code below is for the textfield - i used riverpod to connect it to firestore:
class AddMealPage extends ConsumerWidget {
const AddMealPage({Key? key}) : super(key: key);
static const String route = "/addMeal";
#override
Widget build(BuildContext context, WidgetRef ref) {
final model = ref.read(addMealProvider);
return LoadingLayer(
child: Scaffold(
appBar: AppBar(
elevation: 0,
iconTheme: const IconThemeData(
color: Colors.black,
),
title: const Text(
"Create Meal",
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
backgroundColor: Colors.white,
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.fromLTRB(24, 0, 24, 24),
child: MaterialButton(
padding: const EdgeInsets.all(16),
color: Colors.black,
onPressed: model.enabled
? () async {
try {
await model.writeMeal();
Navigator.pop(context);
} catch (e) {
AppSnackbar(context).error(e);
}
}
: null,
child: const Text(
"Add meal",
style: TextStyle(color: Color.fromARGB(255, 247, 245, 245)),
),
),
),
body: SingleChildScrollView(
child: Container(
padding:
const EdgeInsets.symmetric(vertical: 60.0, horizontal: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
GestureDetector(
onTap: () async {
final picked = await ImagePicker()
.pickImage(source: ImageSource.gallery);
if (picked != null) {
model.file = File(picked.path);
}
},
child: Container(
margin: const EdgeInsets.only(),
width: MediaQuery.of(context).size.width,
height: 210.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image: (model.mealUrl != null || model.file != null)
? DecorationImage(
image: model.file != null
? FileImage(model.file!)
: NetworkImage(model.mealUrl!)
as ImageProvider,
fit: BoxFit.cover,
)
: null),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (model.mealUrl == null && model.file == null)
const Expanded(
child: Center(
child: Icon(
Icons.photo,
),
),
),
const Material(
color: Colors.transparent,
child: Padding(
padding: EdgeInsets.all(8.0),
),
),
],
),
),
),
const SizedBox(
height: 10,
),
const Padding(
padding: EdgeInsets.only(left: 15.0),
child: Text(
"Meal Name",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
),
),
Container(
height: 50,
padding: const EdgeInsets.only(top: 10),
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.symmetric(horizontal: 20),
child: TextFormField(
textInputAction: TextInputAction.done,
initialValue: model.mealName,
maxLines: 1,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Colors.grey),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(color: Colors.grey),
),
),
onChanged: (v) => model.mealName = v,
),
),
I want to display the input value i get from the textfield above in the format of a radioButton on a seperate page :
enum Variant { mealName }
class RadioOption extends StatefulWidget {
const RadioOption({Key? key}) : super(key: key);
#override
State<RadioOption> createState() => _RadioOptionState();
}
class _RadioOptionState extends State<RadioOption> {
Variant? _character = Variant.mealName;
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
RadioListTile<Variant>(
title: const Text('$mealName'),
value: Variant.MealName,
groupValue: _character,
onChanged: (Variant? value) {
setState(() {
_character = value;
});
},
),
I don't see the whole architecture of the app. But if you want to transfer model.mealName, you can make String value (mealName) in your RadioOption, and pass it through the constructor:
final mealName;
RadioOption({required this.mealName});
And then access it in _RadioOptionState by:
title: const Text(widget.mealName);
You can use TextEditingController and add this controller to your TextFormField which have controller properties but you can't use initialValue and controller both so avoid initialValue. To put value you can use controller.text = your_value;
You value will be filled in text field.
To get value from TextFormField Use var newValue = controller.text; and send this newValue to another page in constructor.
I have created a container. His child is a text.
When I tap on the container/text, it display a modal and a Picker.
Then, the user can select a value. Press the confirm button and my text widget should change to display the value selected by the user.
But in my case, it is not updating the value of the text widget. I have used that in the past and it was working very well. But here it is not and I do not see why. I am on this since 8:00. A little help would be appreciated. Many thanks.
int valuePickerUnitSelected =0;
String unitCount = '';
int unitCountInt;
String goal = "";
List <String> unitForHabits = ['Count', 'Minute(s)','Hour(s)','Gramme(s)', 'Pound(s)'];
class AddingHabitDetails extends StatefulWidget {
const AddingHabitDetails({Key key}) : super(key: key);
#override
_AddingHabitDetailsState createState() => _AddingHabitDetailsState();
}
class _AddingHabitDetailsState extends State<AddingHabitDetails> {
BuildContext get ctx => null;
#override
Widget build(BuildContext context) {
return Scaffold(
//drawer: new MyMenu(), //TODO a remettre
appBar: new AppBar(
title: new Text('Habits'),
),
body: Column(
children: [
titleZone('Name'),
textFieldHabits('Habit name', context),
titleZone('Goals'),
FlatButton(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (unitCount.length < 2 )...[
Container(
width: 65,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue,
),
color: Colors.blue,
borderRadius: BorderRadius.all(Radius.circular(20))),
child:
Center(child: Text(
'Time', style: TextStyle(color: Colors.black,))))
]
else
...[
Container(
width: 65,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue,),
color: Colors.blue,
borderRadius: BorderRadius.all(
Radius.circular(20))),
child: Center(
child: Text(
unitCount, style: TextStyle(color: Colors.black,))))
],
],
),
onPressed: () {
setState(() {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return ShowPickerUnite(unitForHabits);
});
},
);
},
),
//ChipGoalV3(ctx),// ChipGoal(),
textFieldHabits('Goals', context),
titleZone('Frequency'),
textFieldHabits('Frequency', context),
titleZone('Time Range'),
titleZone('Reminder'),
titleZone('Habits Term'),
],
),
);
}
}
//########################################################################
class ShowPickerUnite extends StatefulWidget {
List<String> myListUnit;
ShowPickerUnite(this.myListUnit, {Key key}) : super(key: key);
#override
_ShowPickerUniteState createState() => _ShowPickerUniteState(
myListUnit);
}
class _ShowPickerUniteState extends State<ShowPickerUnite> {
List <String> myListUnit;
_ShowPickerUniteState(this.myListUnit);
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
decoration: BoxDecoration(
color: Color(0xffffffff),
border: Border(
bottom: BorderSide(
color: Color(0xffffffff),
width: 0.0,
),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CupertinoButton(
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 5.0,
),
),
DefaultTextStyle(
style: TextStyle(
fontSize: 16.0,
color: Colors.black,
fontWeight: FontWeight.bold),
child: Text('Select what you want'),
),
// Text('Energy Needed', style: TextStyle(fontSize: 12.0, color: Colors.black),
// ),
CupertinoButton(
child: Text('Confirm'),
onPressed: () {
setState(() {
unitCount = unitForHabits[valuePickerUnitSelected];
print(unitCount);
});
Navigator.of(context).pop();
},
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 5.0,
),
),
],
),
),
Container(
//width: 360,
height: 200,
decoration:BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15.0)),
),
child: CupertinoPicker(
backgroundColor: Colors.white ,
useMagnifier: true,
magnification: 1.3,
scrollController: FixedExtentScrollController(initialItem: 0),
itemExtent: 25,
children: [
for (String name in myListUnit)
Center(
child:Text(name)),
],
onSelectedItemChanged: (value) {
setState(() {
valuePickerUnitSelected = value;
// taskEnergy = myListEnergy[valuePickerEnergySelected];
// taskNewValue ['task_Energy'] = taskEnergy;
});
}))
]);
}
}
Widget inputNameHabit (){
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text ('Name Habits',style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold),),
);
}
Widget titleZone (String _titleName){
return Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Text ( _titleName,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold),),
],
),
);
}
Widget textFieldHabits (String item,context){
return TextField(
decoration: InputDecoration(
hintText: item,
filled: true,
fillColor: Colors.grey[300],
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(50)
),
),
onTap: (){
Navigator.push(context,
MaterialPageRoute(
builder: (context) => HabitGoalUnitSelection(), //TODO MODIFIER route selon source
),
);
},);
}
Wait for the dialog to finish and then call setState to update the UI.
Modify this way
onPressed: () async {
await showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return ShowPickerUnite(unitForHabits);
});
setState(() {});
I have 2 variables that can be updated if I pressed a button. _tempQuan1 is not getting updated (immediately) since it is not in the build Widget. On the other hand, _tempQuan2 gets the updated for every button press. Is there a way so that I can get the _tempQuan1 to work same as _tempQuan2?
Note: I have tried to remove all other codes until I found out about the information above.
Edit: I have also tried to make it as a stateless widget and use Getx and make an observable variable but I still unable to do it.
import 'package:flutter/material.dart';
import 'package:awesome_dialog/awesome_dialog.dart';
class ShoppingWidget extends StatefulWidget {
State<StatefulWidget> createState() => ShoppingState();
}
class ShoppingState extends State<ShoppingWidget> {
int _tempQuan1 = 1;
int _tempQuan2 = 1;
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
showBuyPopup() async {
AwesomeDialog(
context: context,
dialogType: DialogType.NO_HEADER,
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: <Widget>[
Container(
width: 32.0,
height: 25.0,
child: Text(
_tempQuan1.toString(),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Material(
child: InkWell(
splashColor: Theme.of(context).primaryColor,
onTap: () {
if (this.mounted) {
setState(() {
_tempQuan1++;
});
}
print('increase');
},
child: Container(
width: 35.0,
height: 32.0,
decoration: BoxDecoration(
color: Theme.of(context).primaryColorDark.withOpacity(0.9),
borderRadius: BorderRadius.circular(8.0),
),
child: Icon(
Icons.add,
color: Colors.white,
size: 18.0,
),
),
),
),
),
],
),
SizedBox(
height: 10.0,
),
],
),
),
buttonsTextStyle: Theme.of(context).textTheme.bodyText2,
showCloseIcon: false,
btnCancelOnPress: () {},
btnOkOnPress: () async {},
)..show();
}
#override
Widget build(BuildContext context) {
print('PATH: item card widget build');
return Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
Text(
_tempQuan2.toString(),
),
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Material(
child: InkWell(
splashColor: Theme.of(context).primaryColor,
onTap: () {
if (this.mounted) {
setState(() {
_tempQuan2++;
});
}
print('increase');
},
child: Container(
width: 35.0,
height: 32.0,
decoration: BoxDecoration(
color: Theme.of(context).primaryColorDark.withOpacity(0.9),
borderRadius: BorderRadius.circular(8.0),
),
child: Icon(
Icons.add,
color: Colors.white,
size: 18.0,
),
),
),
),
),
],
),
Container(
child: ElevatedButton(
onPressed: () {
showBuyPopup();
},
child: Text(
'Button',
),
),
),
],
),
);
}
}
The easiest solution is to move the body of your dialog into it's own stateful widget.. ie something like
AwesomeDialog(
context: context,
body: MyAwesomeDialogBody(tempQuan: _tempQuan2),
).show()
And then have a stateful widget MyAwesomeDialogBody which basically does everything you had previously in the body.
You would also have to pass in some callback so the changes to tempQuan are communicated back to the parent widget..
In my flutter project, I have set one custom drawer.
Here's code for custom drawer-
class AppDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
double defaultScreenWidth = 400.0;
double defaultScreenHeight = 810.0;
ScreenUtil.instance = ScreenUtil(
width: defaultScreenWidth,
height: defaultScreenHeight,
allowFontScaling: true,
)..init(context);
return SizedBox(
width: MediaQuery.of(context).size.width * 0.70,
child: Drawer(
child: Container(
color: Colors.black87,
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
SizedBox(height: ScreenUtil.instance.setHeight(30),),
_createDrawerItem(
icon: Icons.keyboard_arrow_right,
text: 'English to Bangla',
onTap: () =>
Navigator.pushReplacementNamed(context, Routes.englishToBangla)),
Padding(
padding: EdgeInsets.only(left:ScreenUtil.instance.setWidth(20), right: ScreenUtil.instance.setWidth(20)),
child: Divider(
height: ScreenUtil.instance.setHeight(10),
color: Colors.grey,
),
),
],
),
),
),
);
}
Widget _createHeader() {
return DrawerHeader(
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage('path/to/header_background.png'))),
child: Stack(children: <Widget>[
Positioned(
bottom: 12.0,
left: 16.0,
child: Text("Flutter Step-by-Step",
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w500))),
]));
}
Widget _createDrawerItem(
{IconData icon, String text, GestureTapCallback onTap}) {
return ListTile(
title: Padding(
padding: EdgeInsets.only(left: ScreenUtil.instance.setWidth(10)),
child: Row(
children: <Widget>[
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.teal
),
child: Icon(icon, color: Colors.white,)
),
Padding(
padding: EdgeInsets.only(left: ScreenUtil.instance.setWidth(10)),
child: Text(text, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: ScreenUtil.instance.setSp(14) ),),
)
],
),
),
onTap: onTap,
);
}
}
Here's code for the toolBar which is shown beside the drawer icon-
class SearchAppBar extends StatefulWidget implements PreferredSizeWidget {
final PatternCallback onPatternSelected;
SearchAppBar(this.onPatternSelected, {Key key})
: preferredSize = Size.fromHeight(90),
super(key: key);
#override
final Size preferredSize; // default is 56.0
#override
_SearchAppBarState createState() => _SearchAppBarState();
}
class _SearchAppBarState extends State<SearchAppBar> {
TextEditingController _searchTextController = TextEditingController();
#override
Widget build(BuildContext context) {
double defaultScreenWidth = 400.0;
double defaultScreenHeight = 810.0;
ScreenUtil.instance = ScreenUtil(
width: defaultScreenWidth,
height: defaultScreenHeight,
allowFontScaling: true,
)..init(context);
return Container(
color: Colors.white,
child: Row(
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
),
child: Theme(
data:
Theme.of(context).copyWith(primaryColor: Color(0xFFff9900)),
child: TextFormField(
autofocus: false,
style: TextStyle(fontSize: ScreenUtil.instance.setSp(18)),
keyboardType: TextInputType.text,
controller: _searchTextController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Search for any word you want',
hintStyle:
TextStyle(fontSize: ScreenUtil.instance.setSp(16)),
contentPadding: EdgeInsets.symmetric(
vertical: 14,
horizontal: 10),
),
onChanged: (String value) {
widget.onPatternSelected(value);
},
),
),
),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(0),
),
child: InkWell(onTap: (){
if(_searchTextController.text.isNotEmpty) {
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>WordDetailScreen(_searchTextController.text.toLowerCase())));
}
},
child: Icon(Icons.search, color: Colors.blue,))),
SizedBox(width: 15)
],
),
);
}
}
And then, in the class where I want to use this drawer, I have called inside Scaffold like below-
drawer: AppDrawer()
But the problem is this causing a white space beside the drawer icon like below image-
And I am having no idea from where this extra padding or margin is happening. So, I need a solution to reduce this extra white space beside the drawer icon.
You can use Transform.translate to move the search bar to the left:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Builder(builder: (context) {
return IconButton(
icon: Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer(),
);
}),
title: Transform.translate(
offset: Offset(-30.0, 0.0),
child: Text('this is the title') // here you can put the search bar
),
),
drawer: Drawer(
),
);
}
Just add a property called "titleSpacing" in your AppBar Tag,
Sample
appBar: AppBar(
titleSpacing: 0, //Add this line to your code
title: Text(widget.title),
leading: Icon(Icons.android),
),
I'm new to flutter and need to create a gallery app that needs a custom dialog box to show the selected image. How can I implement that?
Use Dialog class which is a parent class to AlertDialog class in Flutter. Dialog widget has a argument , "shape" which you can use to shape the Edges of the Dialog box.
Here is a code sample:
Dialog errorDialog = Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), //this right here
child: Container(
height: 300.0,
width: 300.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(15.0),
child: Text('Cool', style: TextStyle(color: Colors.red),),
),
Padding(
padding: EdgeInsets.all(15.0),
child: Text('Awesome', style: TextStyle(color: Colors.red),),
),
Padding(padding: EdgeInsets.only(top: 50.0)),
TextButton(onPressed: () {
Navigator.of(context).pop();
},
child: Text('Got It!', style: TextStyle(color: Colors.purple, fontSize: 18.0),))
],
),
),
);
showDialog(context: context, builder: (BuildContext context) => errorDialog);}
Screenshot (Null Safe):
Code:
Just call this method:
void showCustomDialog(BuildContext context) {
showGeneralDialog(
context: context,
barrierLabel: "Barrier",
barrierDismissible: true,
barrierColor: Colors.black.withOpacity(0.5),
transitionDuration: Duration(milliseconds: 700),
pageBuilder: (_, __, ___) {
return Center(
child: Container(
height: 240,
child: SizedBox.expand(child: FlutterLogo()),
margin: EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(40)),
),
);
},
transitionBuilder: (_, anim, __, child) {
Tween<Offset> tween;
if (anim.status == AnimationStatus.reverse) {
tween = Tween(begin: Offset(-1, 0), end: Offset.zero);
} else {
tween = Tween(begin: Offset(1, 0), end: Offset.zero);
}
return SlideTransition(
position: tween.animate(anim),
child: FadeTransition(
opacity: anim,
child: child,
),
);
},
);
}
On a button click show dialog as -
showDialog(
context: context,
builder: (_) => LogoutOverlay(),
);
Dialog design with two buttons -
class LogoutOverlay extends StatefulWidget {
#override
State<StatefulWidget> createState() => LogoutOverlayState();
}
class LogoutOverlayState extends State<LogoutOverlay>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> scaleAnimation;
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 450));
scaleAnimation =
CurvedAnimation(parent: controller, curve: Curves.elasticInOut);
controller.addListener(() {
setState(() {});
});
controller.forward();
}
#override
Widget build(BuildContext context) {
return Center(
child: Material(
color: Colors.transparent,
child: ScaleTransition(
scale: scaleAnimation,
child: Container(
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(15.0),
height: 180.0,
decoration: ShapeDecoration(
color: Color.fromRGBO(41, 167, 77, 10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0))),
child: Column(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(
top: 30.0, left: 20.0, right: 20.0),
child: Text(
"Are you sure, you want to logout?",
style: TextStyle(color: Colors.white, fontSize: 16.0),
),
)),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: ButtonTheme(
height: 35.0,
minWidth: 110.0,
child: RaisedButton(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
splashColor: Colors.white.withAlpha(40),
child: Text(
'Logout',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
fontSize: 13.0),
),
onPressed: () {
setState(() {
Route route = MaterialPageRoute(
builder: (context) => LoginScreen());
Navigator.pushReplacement(context, route);
});
},
)),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 10.0, top: 10.0, bottom: 10.0),
child: ButtonTheme(
height: 35.0,
minWidth: 110.0,
child: RaisedButton(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
splashColor: Colors.white.withAlpha(40),
child: Text(
'Cancel',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
fontSize: 13.0),
),
onPressed: () {
setState(() {
/* Route route = MaterialPageRoute(
builder: (context) => LoginScreen());
Navigator.pushReplacement(context, route);
*/ });
},
))
),
],
))
],
)),
),
),
);
}
}
You just put this class in your project and call its method for showing dialog. Using this class you don't need to write dialog code everywhere
class DialogUtils {
static DialogUtils _instance = new DialogUtils.internal();
DialogUtils.internal();
factory DialogUtils() => _instance;
static void showCustomDialog(BuildContext context,
{#required String title,
String okBtnText = "Ok",
String cancelBtnText = "Cancel",
#required Function okBtnFunction}) {
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text(title),
content: /* Here add your custom widget */,
actions: <Widget>[
FlatButton(
child: Text(okBtnText),
onPressed: okBtnFunction,
),
FlatButton(
child: Text(cancelBtnText),
onPressed: () => Navigator.pop(context))
],
);
});
}
}
You can call this method like :
GestureDetector(
onTap: () =>
DialogUtils.showCustomDialog(context,
title: "Gallary",
okBtnText: "Save",
cancelBtnText: "Cancel",
okBtnFunction: () => /* call method in which you have write your logic and save process */),
child: Container(),
)
Alert Dialog
Custom Dialog
Full-Screen Dialog
ref: Flutter Alert Dialog to Custom Dialog | by Ishan Fernando | CodeChai | Medium
Alert Dialog
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Alert Dialog"),
content: Text("Dialog Content"),
actions: [
TextButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
},
);
Custom Dialog
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20.0)), //this right here
child: Container(
height: 200,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'What do you want to remember?'),
),
SizedBox(
width: 320.0,
child: RaisedButton(
onPressed: () {},
child: Text(
"Save",
style: TextStyle(color: Colors.white),
),
color: const Color(0xFF1BC0C5),
),
)
],
),
),
),
);
});
Full-Screen Dialog
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: MaterialLocalizations.of(context)
.modalBarrierDismissLabel,
barrierColor: Colors.black45,
transitionDuration: const Duration(milliseconds: 200),
pageBuilder: (BuildContext buildContext,
Animation animation,
Animation secondaryAnimation) {
return Center(
child: Container(
width: MediaQuery.of(context).size.width - 10,
height: MediaQuery.of(context).size.height - 80,
padding: EdgeInsets.all(20),
color: Colors.white,
child: Column(
children: [
RaisedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
"Save",
style: TextStyle(color: Colors.white),
),
color: const Color(0xFF1BC0C5),
)
],
),
),
);
});
An General E.g
showDialog(context: context,builder: (context) => _onTapImage(context)); // Call the Dialog.
_onTapImage(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: <Widget>[
Image.network('https://via.placeholder.com/150',fit: BoxFit.contain,), // Show your Image
Align(
alignment: Alignment.topRight,
child: RaisedButton.icon(
color: Theme.of(context).accentColor,
textColor: Colors.white,
onPressed: () => Navigator.pop(context),
icon: Icon(
Icons.close,
color: Colors.white,
),
label: Text('Close')),
),
],
);
}
I usually build a wrapper for the dialog that matches the app theme and avoids much redundant code.
PlaceholderDialog
class PlaceholderDialog extends StatelessWidget {
const PlaceholderDialog({
this.icon,
this.title,
this.message,
this.actions = const [],
Key? key,
}) : super(key: key);
final Widget? icon;
final String? title;
final String? message;
final List<Widget> actions;
#override
Widget build(BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
icon: icon,
title: title == null
? null
: Text(
title!,
textAlign: TextAlign.center,
),
titleTextStyle: AppStyle.bodyBlack,
content: message == null
? null
: Text(
message!,
textAlign: TextAlign.center,
),
contentTextStyle: AppStyle.textBlack,
actionsAlignment: MainAxisAlignment.center,
actionsOverflowButtonSpacing: 8.0,
actions: actions,
);
}
}
Usage
showDialog(
context: context,
builder: (ctx) => PlaceholderDialog(
icon: Icon(
Icons.add_circle,
color: Colors.teal,
size: 80.0,
),
title: 'Save Failed',
message: 'An error occurred when attempt to save the message',
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(),
child: Text('!Got It'),
),
],
),
);
Result
You can now use AlertDialog and in content build your widget.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
backgroundColor: Colors.green,
content: Container(
height:200,
width:200,
decoration: BoxDecoration(
image: DecorationImage(
image: FileImage(filepath),
fit: BoxFit.cover))),}),
There's a working solution in my case:
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('AlertDialog Title'),
content: SingleChildScrollView(
child: Column(
children: <Widget>[
Text('This is a demo alert dialog.'),
Text('Would you like to confirm this message?'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('Confirm'),
onPressed: () {
print('Confirmed');
Navigator.of(context).pop();
},
),
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Hope this is helpful:
I've made static function in a separate class:
import 'package:flutter/material.dart';
import 'package:flutter_application_1/TGColors.dart';
class TGDialog
{
static doNothing() { } // stub needed for Function parameters
/// Returns an AlertDialog with most optional parameters
static AlertDialog dlg( BuildContext context,
{ String txtTitle = 'WHAT? no title?' ,
String txtMsg = 'WHAT? no content?',
String txtBtn1 = 'CANCEL' ,
String txtBtn2 = 'OK' ,
Function funcBtn1 = doNothing ,
Function funcBtn2 = doNothing ,
Color colBackground = TGColors.Orange ,
Color colText = TGColors.Indigo } )
{
return
AlertDialog(
backgroundColor : colBackground,
title : Text(txtTitle),
content : Text(txtMsg),
actions : <Widget>
[
TextButton(
onPressed : () => { funcBtn1(), Navigator.pop(context,'Cancel')},
child : Text(txtBtn1, style: TextStyle(color: colText)),
),
TextButton(
onPressed :() => { funcBtn2(),Navigator.pop(context) },
child : Text(txtBtn2, style: TextStyle(color: colText)),
),
],
);
}
}
An example:
Positioned( bottom: 1, left: (screenW / 5.6),
child : FloatingActionButton(
heroTag : 'clear',
onPressed :() => showDialog<String>
(
context : context,
builder : (BuildContext context) =>
///////////////////////////////////////////////////////
TGDialog.dlg( context,
txtTitle : 'Clear Order?',
txtMsg : 'This resets all item counts' ,
funcBtn2 : resetOrder)
///////////////////////////////////////////////////////
),
child : const Text('clear\nall', textAlign: TextAlign.center),
shape : RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
),
),
etc.
Btw: I like CSS webcolors so I defined them in a separate class
like so:
import 'dart:ui';
/// Contains mainly web colors (based on CSS)
///
/// Usage e.g: ... = TGcolors.CornFlowerBlue
class TGColors
{
static const PrimaryColor = Color(0xFF808080);
static const AliceBlue = Color(0xFFF0F8FF);
static const AntiqueWhite = Color(0xFFFAEBD7);
static const Aqua = Color(0xFF00FFFF);
static const Aquamarine = Color(0xFF7FFFD4);
// etc.
Custom Alert Dialog in Flutter
void openAlert() {
dialog = Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0)),
//this right here
child: Container(
height: 350.0,
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
ClipRRect(
child: Image.asset(
"assets/images/water1.jpg",
width: double.infinity,
height: 180,
fit: BoxFit.cover,
),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16), topRight: Radius.circular(16)),
),
Container(
margin: EdgeInsets.only(top: 16),
decoration: boxDecorationStylealert,
width: 200,
padding: EdgeInsets.symmetric(horizontal: 8),
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
showToastMessage("-");
},
child:Image.asset("assets/images/subtraction.png",width: 30,height: 30,)),
Text(
"1",
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: black_color),
),
GestureDetector(
onTap: () {
showToastMessage("+");
},
child:Image.asset("assets/images/add.png",width: 30,height: 30,)),
],
),
),
Expanded(child: Container()),
Row(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 12, right: 6),
child: MaterialButton(
onPressed: cancelClick,
color: green_color,
child: Text(
"CANCEL",
style: TextStyle(fontSize: 12, color: white_color),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 6, right: 12),
child: MaterialButton(
onPressed: okClick,
color: green_color,
child: Text(
"OK",
style: TextStyle(fontSize: 12, color: white_color),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
),
),
)
],
)
],
),
),
);
showDialog(
context: context, builder: (BuildContext context) => dialog);
}