I want to have a modal bottom sheet that I can scroll through as normal without closing the modal bottom sheet. Then, when I'm at the top of my list, I want to be able to close the Modal Bottom Sheet with a scroll gesture.
I would like to add the YouTube style modal bottom sheet shown in the video to my app, but unfortunately I don't know how to do it.
This is the link to the video that shows what I mean: https://drive.google.com/file/d/1977Ptq4Sox6WKGQkiTbCH_zydn8Mu05o/view?usp=sharing
This is inside my Profile Screen:
#override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: Container(
height: MediaQuery.of(context).size.height * 0.95,
margin: EdgeInsets.only(bottom: 5, left: 10, right: 10),
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 1.5),
borderRadius: BorderRadius.circular(25),
color: Colors.white,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(23),
child: DraggableScrollableSheet(
initialChildSize: 1,
minChildSize: 0.5,
maxChildSize: 1,
expand: false,
builder: (BuildContext context, ScrollController _scrollController) {
return SingleChildScrollView(
controller: _scrollController,
child: Column(
children: [
Container(
height: 590,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 1.5, color:
Colors.black),
),
color: Colors.white,
),
child: Stack(
children: [
InteractiveViewer(
transformationController:
_zoomProfilePictureController,
minScale: 1,
maxScale: 3,
onInteractionEnd: (ScaleEndDetails endDetails) {
setState(() {
_zoomProfilePictureController.value =
Matrix4.identity();
});
},
child: Swiper(
physics: NeverScrollableScrollPhysics(),
itemBuilder:
(BuildContext context, int imageIndex) {
return Hero(
tag: "Profile",
child: CachedNetworkImage(
imageUrl: widget.user.imageUrl[imageIndex],
fit: BoxFit.cover,
useOldImageOnUrlChange: true,
placeholder: (context, url) => Center(
child: CircularProgressIndicator(
strokeWidth: 3,
valueColor: AlwaysStoppedAnimation<Color>(
primaryColor.withOpacity(0.7),
),
),
),
errorWidget: (context, url, error) => Icon(
Icons.error_outline,
size: 30,
color: Colors.red,
),
),
);
},
itemCount: widget.user.imageUrl.length,
pagination: SwiperPagination(
alignment: Alignment.topCenter,
margin: EdgeInsets.all(0),
builder: DotSwiperPaginationBuilder(
color: Colors.white.withOpacity(0.7),
size: 8,
activeColor: widget.user.imageUrl.length > 1
? primaryColor
: Colors.transparent,
activeSize: 10,
),
),
control: widget.user.imageUrl.length > 1
? SwiperControl(
padding: const EdgeInsets.only(top: 250),
color: Colors.transparent,
disableColor: Colors.transparent,
size: 228,
)
: null,
loop: false,
),
),
This is how I call the BottomSheet:
ListTile(
onTap: () => showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
builder: (context) {
return ProfileInformationHomeScreen(
secondUser,
widget.currentUser,
);
},
),
it's DraggableScrollableSheet.
create a widget for bottomSheet.
#override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
child: DraggableScrollableSheet(
///* it will be always visible 95% of screen,
///* if we drag down at 50% it will close the sheet
initialChildSize: 0.95,
minChildSize: 0.5,
maxChildSize: .95,
expand: false,
builder: (BuildContext context, c) {
return Container(
color: Colors.white,
child: ListView(
controller: c,
children: [
/// your widgets
call a method to showModalBottomSheet.
_showBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => DestinationBottomSheetWidget(),
);
}
To close the buttomSheet you can drag or use a button inside DraggableScrollableSheet builder and use Navigator.of(context).pop().
I do like this and add item of ListView
/// heading
Padding(
padding: EdgeInsets.only(
left: 20,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: Icon(
Icons.close,
color: Colors.grey,
),
),
Text(
"Title",
textAlign: TextAlign.center,
),
///* this empty widget will handle the spaces
Icon(
Icons.close,
color: Colors.grey.withOpacity(0.0),
),
],
),
),
for more flutter doc youtube
After doing a bit of research, I tried to wrap ListTiles with InkWell to get the onTap ripple effect, but it doesn't seem to work. This is what I have:
return AnimationLimiter(
child: Scrollbar(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.myItems.length,
itemBuilder: (context, index) => AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 300),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: Material(
/// child: Ink( also tried with Ink and no Ink and no Material just InkWell but no ripple
child: InkWell(
onTap: () => widget.nav(widget.myItems[index]),
splashColor: Colors.red,
child: Card(
child: _itemTile(index),
),
),
),
),
),
),
),
),
);
The ListTile:
return ListTile(
dense: true,
trailing: Icon(Icons.keyboard_arrow_right),
leading: category,
title: Text(
item.title,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
);
I managed to get the ripple effect working by doing onTap: () => {} to the InkWell. But after adding the GestureDetector, the Ripple is gone again.
child: InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () {},
splashColor: Colors.red,
child: GestureDetector(
onTap: () => widget.nav(widget.myItems[index]),
child: _itemTile(index),
),
),
I even tried this, ripple works, but it the widget.nav function doesn't get called:
Stack(
children: [
Card(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
margin:
EdgeInsets.only(bottom: 5.0, left: 2.0, right: 2.0),
child: GestureDetector(
onTap: () {
widget.nav(widget.myItems[index]);
},
child: _itemTile(index),
),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => {},
),
),
)
],
),
Edit* Adding the nav function:
_navToItem(item) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Item(
items: _activityItems.length > 0 ? _activityItems : _items,
showAd: false,
user: userStream,
item: item,
favorites: _favorites,
),
),
);
}
ListTile has a ripple effect by default, so you shouldn't need to add an inkwell. If there isn't a ripple, one of the children is probably causing some issues. Try removing some and see if that helps.
Example
You're correct in using the Stack.
It's necessary due to the way the widget tree is rendered from bottom up, layering each widget on top of each other (which blocks the visual effect of splash if there are children below it.)
The GestureDetector you have in your Stack example won't ever get the tap gesture, cause InkWell below it is taking the event.
Something like this work for you? (Move your widget.nav call to the InkWell onTap:.)
Stack(
children: [
Card(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
margin:
EdgeInsets.only(bottom: 5.0, left: 2.0, right: 2.0),
// GESTUREDETECTOR Removed ****************
child: Text('itemTile goes here'),
),
Positioned.fill(
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () => print('InkWell tapped! Put widget.nav here!'),
),
),
)
],
)
Please try to understand the concept of it. You should provide some margin to the widget to show the effects. You didn't provide any margin or align so it has no space to show the effects.
Below exp. show the effects in all the page because center creates margin from all the side. The Centre aligns its child widget from the top, left, right and bottom.
Widget build(BuildContext context) {
return Center(
child: Material(
child: new InkWell(
onTap: () {
print("tap");
},
child: Center(
child: Container(
width: 200.0,
height: 200.0,
color: Colors.red,
),
),
),
),
);
}
In your case:
return AnimationLimiter(
child: Scrollbar(
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.myItems.length,
itemBuilder: (context, index) => AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 300),
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: Material(
/// child: Ink( also tried with Ink and no Ink and no Material just InkWell but no ripple
child: InkWell(
onTap: () => widget.nav(widget.myItems[index]),
splashColor: Colors.red,
child: Center(
child: Card(
child: _itemTile(index),
),
),
),
),
),
),
),
),
),
);
For ListTile case try passing custom ripple color. May be your background and your ripple effect color is same.
There is no need to wrap ListTile with InkWell because it already does it under the hood. We could do this with a Material widget to preserve the ripple effect and to act like a Card widget:
Material(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
elevation: 1,
child: ListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
leading: Text('Hello World'),
onTap: () => print('Pressed ListTile'),
),
),
Output:
Please change your code
Card(child: InkWell(child: ListTile(), onTab: () {},),),
First of all Card widget, its child Inkwell and then ListTile.
I'm working with flutter. I want to make a CupertinoAlertDialog(iOS style is required). My problem is UI designers require the background color of the alert dialog should be #F0F0F0. But I can only adjust its theme into dark or light(e.g. following picture). The code I completed is placed below.
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return Theme(
data: ThemeData.dark(),
child: CupertinoAlertDialog(
title: Text('Title'),
content: Text('Some message here'),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancle'),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
),
],
),
);
}
);
Is that possible? Thanks for any advice.
If I recall correctly, the background color for CupertinoAlertDialog is hardcoded. However, you can create a custom dialog that can change the background color of it as well as the functions of the buttons.
You need to create a type Dialog for the showDialog function instead of showCupertinoDialog:
Dialog customDialog = Dialog(
backgroundColor: Color(0xfff0f0f0), // your color
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(40)), // change 40 to your desired radius
child: CustomAlertDialog(),
);
I also created a stateless widget called CustomAlertDialog, but if you don't want to, you can replace the CustomAlertDialog() with its content.
class CustomAlertDialog extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height: 150,
child: Column(
children: [
Expanded(
flex: 2,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey, width: 1),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
child: Center(
child: Text(
"Title",
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
),
),
),
Container(
child: Center(
child: Text("Some message here"),
),
),
],
),
),
),
Expanded(
flex: 1,
child: Row(
children: [
Expanded(
flex: 1,
child: GestureDetector(
child: Container(
decoration: BoxDecoration(
border: Border(
right: BorderSide(color: Colors.grey, width: 1),
),
),
child: Center(
child: Text("Cancel"),
),
),
onTap: () {
Navigator.of(context).pop(); // replace with your own functions
},
),
),
Expanded(
flex: 1,
child: GestureDetector(
child: Container(
child: Center(
child: Text("OK"),
),
),
onTap: () {
Navigator.of(context).pop(); // replace with your own functions
},
),
),
],
),
),
],
),
);
}
}
Lastly, replace your whole showCupertinoDialog with this showDialog function:
showDialog(
barrierDismissible: true, // set false if you dont want the dialog to be dismissed when user taps anywhere [![enter image description here][1]][1]outside of the alert
context: context,
builder: (context) {
return customDialog;
},
);
Result: https://i.stack.imgur.com/cV13A.png
I have a ListView where I want to implement a nice way to delete list items using a bottom sheet with actions on. Initially I went down the path of simply calling showBottomSheet() in the onLongPress event handler for my list items, which would successfully open a bottom sheet with my action buttons on. However, this would automatically add a back button to the AppBar which is not what I want.
I then went down the route of trying out animations, such as SlideTransition and AnimatedPositioned:
class FoldersListWidget extends StatefulWidget {
#override
_FoldersListWidgetState createState() => _FoldersListWidgetState();
}
class _FoldersListWidgetState extends State<FoldersListWidget>
with SingleTickerProviderStateMixin {
double _bottomPosition = -70;
#override
Widget build(BuildContext context) {
return Stack(
children: [
FutureBuilder<List<FolderModel>>(
future: Provider.of<FoldersProvider>(context).getFolders(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
final folder = snapshot.data[i];
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
elevation: 1,
child: ListTile(
title: Text(folder.folderName),
leading: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 50,
child: Consumer<FoldersProvider>(
builder:
(BuildContext context, value, Widget child) {
return value.deleteFolderMode
? CircularCheckBox(
value: false,
onChanged: (value) {},
)
: Icon(
Icons.folder,
color: Theme.of(context).accentColor,
);
},
),
),
],
),
subtitle: folder.numberOfLists != 1
? Text('${folder.numberOfLists} items')
: Text('${folder.numberOfLists} item'),
onTap: () {},
onLongPress: () {
Provider.of<FoldersProvider>(context, listen: false)
.toggleDeleteFolderMode(true); // removes fab from screen
setState(() {
_bottomPosition = 0;
});
},
),
);
},
);
},
),
AnimatedPositioned(
bottom: _bottomPosition,
duration: Duration(milliseconds: 100),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
topRight: Radius.circular(25),
),
child: Container(
height: 70,
width: MediaQuery.of(context).size.width,
color: Theme.of(context).colorScheme.surface,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
child: IconAboveTextButton(
icon: Icon(Icons.cancel),
text: 'Cancel',
textColour: Colors.black,
opacity: 0.65,
onTap: () => setState(() {
_bottomPosition = -70;
}),
),
),
VerticalDivider(
color: Colors.black26,
),
Expanded(
child: IconAboveTextButton(
icon: Icon(Icons.delete),
text: 'Delete',
textColour: Colors.black,
opacity: 0.65,
),
),
],
),
),
),
),
],
);
}
}
This slides the bottom Container on and off the screen but my issue is that it covers the last list item:
Could anyone suggest a better way of doing this or simply a way to adjust the height of the ListView so that when the Container slides up, the ListView also slides up.
Wrap ListView.builder inside a container and set its bottom padding as (70+16)
70 (height of bottom sheet), 16 (some default padding to make it look better if you like).
return Container(
padding: EdgetInset.ony(bottom: (70+16)),
child:ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
.....
.....
I wonder how to change the default width of an AlertDialog, I only succeeded to change the border radius :
Here is my code :
showDialog(
context: context,
builder: (_) =>
new AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))
),
content: ProductPreviewScreen(),
)
);
Result expected :
Any idea?
As of May 2020, if you want to change the inset padding of a dialog, all you have to do is use the Dialog class and override the 'insetPadding' property. You can make a dialog extend all the way to the screen edges if you want to.
You can also make some cool custom dialogs by making the dialog surface itself transparent and then add whatever widgets you want. For example:
showDialog(Dialog(
backgroundColor: Colors.transparent,
insetPadding: EdgeInsets.all(10),
child: Stack(
overflow: Overflow.visible,
alignment: Alignment.center,
children: <Widget>[
Container(
width: double.infinity,
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.lightBlue
),
padding: EdgeInsets.fromLTRB(20, 50, 20, 20),
child: Text("You can make cool stuff!",
style: TextStyle(fontSize: 24),
textAlign: TextAlign.center
),
),
Positioned(
top: -100,
child: Image.network("https://i.imgur.com/2yaf2wb.png", width: 150, height: 150)
)
],
)
));
Results in:
This is much more simple then the other answers make it out to be. Just use a builder to change the size of the dialog as it is being built(constructed, instantiated in other languages). This means you can also query the screen size and make a decision on how much space you want depending on said screen size. For example more space on a tablet then on a phone. You can make Scaffold a child of the Container if you need the App bar and other functions.
showDialog(
context: context,
builder: (_) => new AlertDialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(
Radius.circular(10.0))),
content: Builder(
builder: (context) {
// Get available height and width of the build area of this widget. Make a choice depending on the size.
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Container(
height: height - 400,
width: width - 400,
);
},
),
)
);
Examples of different sizes:
Optionally add these to remove unneeded inner/outer border space.
insetPadding: EdgeInsets.zero,
contentPadding: EdgeInsets.zero,
clipBehavior: Clip.antiAliasWithSaveLayer,
Using built-in dialog:
To increase the width:
AlertDialog(
title: Text("AlertDialog"),
insetPadding: EdgeInsets.zero,
)
To decrease the width:
AlertDialog(
title: Text("AlertDialog"),
insetPadding: EdgeInsets.symmetric(horizontal: 100),
)
Using custom dialog:
Call this method:
showGeneralDialog(
context: context,
barrierColor: Colors.black.withOpacity(0.5),
pageBuilder: (_, __, ___) {
return Material(
color: Colors.transparent,
child: Center(
child: Container(
color: Colors.white, // Dialog background
width: 120, // Dialog width
height: 50, // Dialog height
child: SingleChildScrollView(
child: Column(
children: [
Text('I am a small Dialog'),
],
),
),
),
),
);
},
);
You could try to wrap your AlertDialog widget with ConstrainedBox widget as suggested in here and set your desired value for maxWidth parameter.
UPDATED
I just looked at the code of the parent of the AlertDialog widget which is the Dialog widget and found out that it wrapped its child with a ConstrainedBox widget with a minWidth of 280 pixels. This is the reason why we can't change the width of the AlertDialog widget.
Fortunately, there are two things that we can do. First option would be to alter the default minWidth of the Dialog Widget inside the dialog.dart file. Note that changing this would affect all of your flutter projects that uses the Dialog widget.
//inside dialog.dart
class Dialog extends StatelessWidget {
...
#override
Widget build(BuildContext context) {
final DialogTheme dialogTheme = DialogTheme.of(context);
return AnimatedPadding(
padding: MediaQuery.of(context).viewInsets + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
duration: insetAnimationDuration,
curve: insetAnimationCurve,
child: MediaQuery.removeViewInsets(
removeLeft: true,
removeTop: true,
removeRight: true,
removeBottom: true,
context: context,
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(minWidth: 280.0), // You can set your desired value for minWidth here
child: Material(
elevation: 24.0,
...
You can then use the AlertDialog like this:
showDialog(
context: context,
builder: (_) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))
),
contentPadding: EdgeInsets.all(0.0),
content: ProductPreviewScreen(),
)
)
);
The other way would be to create our own customize dialog.
showDialog(
context: context,
builder: (_) => Center( // Aligns the container to center
child: Container( // A simplified version of dialog.
width: 100.0,
height: 56.0,
color: Colors.pink,
)
)
);
Use Padding widget
Padding(
padding: EdgeInsets.only(left: 50.0, right: 50.0),
child://AlertDialog or any other Dialog you can use
Dialog(
elevation: 0.0,
backgroundColor: Colors.transparent,
child: Container(
width: 10.0,
height: 50.0,
color: Colors.red,
)
))
My solution is to enclose the Dialog in a widget that defeats the extra padding added by the Dialog class by modifying the MediaQueryData.
import 'package:myapp/widgets/dialog_inset_defeat.dart';
...
showDialog(
context: context,
builder: (_) => DialogInsetDefeat(
context: context,
child: SimpleDialog(...),
)
);
... or use showDialogWithInsets() for custom values:
showDialogWithInsets(
context: context,
edgeInsets: EdgeInsets.symmetric(horizontal: 8),
builder: (_) => SimpleDialog(...),
)
);
File dialog_inset_defeat.dart
import 'package:flutter/material.dart';
/// A widget to defeat the hard coded insets of the [Dialog] class which
/// are [EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0)].
///
/// See also:
///
/// * [Dialog], for dialogs that have a message and some buttons.
/// * [showDialog], which actually displays the dialog and returns its result.
/// * <https://material.io/design/components/dialogs.html>
/// * <https://stackoverflow.com/questions/53913192/flutter-change-the-width-of-an-alertdialog>
class DialogInsetDefeat extends StatelessWidget {
final BuildContext context;
final Widget child;
final deInset = EdgeInsets.symmetric(horizontal: -40, vertical: -24);
final EdgeInsets edgeInsets;
DialogInsetDefeat({#required this.context, #required this.child, this.edgeInsets});
#override
Widget build(BuildContext context) {
var netEdgeInsets = deInset + (edgeInsets ?? EdgeInsets.zero);
return MediaQuery(
data: MediaQuery.of(context).copyWith(viewInsets: netEdgeInsets),
child: child,
);
}
}
/// Displays a Material dialog using the above DialogInsetDefeat class.
/// Meant to be a drop-in replacement for showDialog().
///
/// See also:
///
/// * [Dialog], on which [SimpleDialog] and [AlertDialog] are based.
/// * [showDialog], which allows for customization of the dialog popup.
/// * <https://material.io/design/components/dialogs.html>
Future<T> showDialogWithInsets<T>({
#required BuildContext context,
bool barrierDismissible = true,
#required WidgetBuilder builder,
EdgeInsets edgeInsets,
}) {
return showDialog(
context: context,
builder: (_) => DialogInsetDefeat(
context: context,
edgeInsets: edgeInsets,
child: Builder(builder: builder),
),
// Edited! barrierDismissible: barrierDismissible = true,
barrierDismissible: barrierDismissible,
);
}
Works for me as of Flutter 1.8.3. YMMV
use Dialog()
Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
insetPadding: EdgeInsets.all(15),
child: SingleChildScrollView(
child: Container(),
),
),
);
Medling with insetWidth and future builder etc. didn't work for me - just editing the content prop's width worked perfectly.
showDialog(
context: context,
builder: (context) {
Future.delayed(Duration(seconds: 1000), () {
Navigator.of(context).pop(true);
});
return AlertDialog(
insetPadding: EdgeInsets.all(8.0),
title: Text(
"Time to go pro!",
textAlign: TextAlign.center,
),
content: Container(
width: MediaQuery.of(context).size.width,
child: BuySheet(
applePayEnabled: applePayEnabled,
googlePayEnabled: googlePayEnabled,
applePayMerchantId: applePayMerchantId,
squareLocationId: squareLocationId),
),
);
});
I finally found a way to change the width of an AlertDialog.
Just wrap the "content" with a Container, and set the width to it.
return AlertDialog(
...
content: Container(
width: MediaQuery.of(context).size.width*0.45,
child: ...
AlertDialog with width modified
You can change the AlertDialog property insetPadding it will be a simple way for you.
void alertBox() {
showDialog(
context: context,
builder: (context) => AlertDialog(
insetPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
// (horizontal:10 = left:10, right:10)(vertical:10 = top:10, bottom:10)
contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
content: Container(
width: MediaQuery.of(context).size.width - 20,
// width = device width minus insetPadding = deviceWidth - 20 (left:10, right:10 = 20)
height: MediaQuery.of(context).size.height - 20,
// height = device height minus insetPadding = deviceHeight - 20 (top:10, bottom:10 = 20)
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Card(
margin: EdgeInsets.zero,
color: Colors.amber,
),
),
),
),
);
}
Refer this code. you can change width and height of dialogue box by setting insetPadding, because it taking default padding so we need to change like this.
showDialog(
context: context,
builder: (_) =>
Dialog(
insetPadding: EdgeInsets.symmetric(horizontal: 2.0, vertical: 2.0),
backgroundColor: Colors.transparent,
child: Container(
width: double.infinity,
height: MediaQuery.of(context).size.height*0.7 ,
decoration: BoxDecoration(
color: Colors.grey[900],
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: (){
Navigator.pop(context);
},
child: Icon(Icons.close,color: Colors.grey,)),
],
),
),
Text("select your avatar",style: TextStyle(color: white,fontWeight: FontWeight.bold),),
],
),
),
),
);
:
return Dialog(
backgroundColor: Colors.white,
insetPadding: EdgeInsets.all(10.0),
child: Container(
width: double.infinity,
use insetpadding where you are returning Dialog and give it a double value, For my case, i gave it a 10.0
insetPadding: EdgeInsets.all(10.0), you can give it a custom height
Hello you can actually use insetPadding and use a column inside content that will contain a SizedBox(width:MediaQuery.of(context).size.width).The only difference is that I used AlertDialog. Bellow is the way it worked for me. You can set dialog width by changing padding inside insetPadding. Hope i helped :).
dialog(){
TextEditingController controller = TextEditingController();
return showDialog(
context: context,
barrierDismissible: true,
builder: (_) => AlertDialog(
insetPadding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * 0.08),
content: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 16,
width: MediaQuery.of(context).size.width,
),
Text(
'Hello',
),
SizedBox(
height: 15,
),
Text(
'Description',
),
TextField(
controller: controller,
style: TextStyle(
color: Colors.black,
),
),
],
),
),
actions: [
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
);
}
This is how it looks like
https://i.stack.imgur.com/bvKpP.png
Add InsetPadding property like this
insetPadding: EdgeInsets.zero
AlertDialog(
title: Center(child: Text("$title")),
------------------------->Here we added the property
insetPadding: EdgeInsets.zero,
titlePadding: EdgeInsets.only(top: 14.0, bottom: 4),
content: Container(
height: 50,
child: TextFormField(
controller: find_controller,
decoration: InputDecoration(
suffixIcon: context.watch<MediaProvider>().isChangeDialog
? IconButton(
onPressed: () {
clearController(find_controller);
},
icon: Icon(Icons.clear))
: null,
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.deepPurpleAccent)),
hintText: 'Id',
),
onChanged: (val) {
if (val.isNotEmpty)
context.read<MediaProvider>().isChangeDialog = true;
else
context.read<MediaProvider>().isChangeDialog = false;
},
),
),
actions: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(4.0),
child: OutlinedButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Align(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Icon(Icons.clear),
),
),
Text("Cancel")
],
),
onPressed: () {
context.read<MediaProvider>().isChangeDialog = false;
Navigator.of(context).pop();
}),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: ElevatedButton(
onPressed: context.watch<MediaProvider>().isChangeDialog
? () {
context.read<MediaProvider>().isChangeDialog = false;
okCallback;
}
: null,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Align(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Icon(Icons.check),
),
),
Text("OK")
],
)),
)
],
),
],
);
Before
After
The solution that worked for me.
Set the insetPadding of the AlertDialog.
Plus, wrap the content in a SizedBox and set the width to MediaQuery.of(context).size.width.
return AlertDialog(
content: SizedBox(
width: MediaQuery.of(context).size.width,
child: const Text("Content"),
),
insetPadding: const EdgeInsets.all(10),
);
Setting just the insetPadding alone does not work.
return Dialog(
insetPadding: EdgeInsets.symmetric(
horizontal: X,
),
);
I found the simplest way... just add insetPadding: EdgeInsets.zero, and it will expand to max size width:
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Center(child: Text("Send Message", style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),)),
backgroundColor: Colors.indigo[700],
insetPadding: EdgeInsets.zero,
content:
As a workaround, you can play with the dialog title, in most cases the dialog will expand horizontally to accommodate the title. So you can create big title to make sure the dialog will take max width. Obviously you can't just put long title, but you can build your title of two text widgets, where one of them has text color matching background. For the case where no title should be shown:
showDialog(
context: context,
builder: (_) =>
new AlertDialog(
title: Text('hidden title, just set font text to the same as background.',
style: TextStyle(color: Colors.white)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))
),
content: ProductPreviewScreen(),
)
);
I am using get package and it is wonderful. use its dialog, easily sizable
Get.generalDialog(pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation,) {
return SimpleDialog(
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(Constants.padding), ),
elevation: 0, backgroundColor: Colors.transparent,
children: [Center(child: Stack(
children: <Widget>[
Container(width: Get.width * 0.95,
padding: const EdgeInsets.only(left: Constants.padding,top: Constants.avatarRadius
+ Constants.padding, right: Constants.padding,bottom: Constants.padding
),
margin: const EdgeInsets.only(top: Constants.avatarRadius),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Get.theme.scaffoldBackgroundColor,
borderRadius: BorderRadius.circular(Constants.padding),
boxShadow: const [
BoxShadow(color: Colors.black,offset: Offset(0,10), blurRadius: 10 ),
]
),
child: Text('body'),
),
Positioned(
left: Constants.padding, right: Constants.padding,
child: CircleAvatar(
backgroundColor: Colors.blueAccent, radius: Constants.avatarRadius,
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(Constants.avatarRadius)),
child: Icon(Icons.done, size: 24, color: Colors.white,)
),
),
),
Positioned(
left: 0,
//right: Constants.padding,
child: CircleAvatar(
backgroundColor: Colors.blueAccent, radius: Constants.avatarRadius,
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(Constants.avatarRadius)),
child: InkWell(child: const Icon(Icons.close, size: 24, color: Colors.white,), onTap: (){Get.back();},)
),
),
),
],
))],
);
}, barrierDismissible: true, barrierLabel: '');
Use width: MediaQuery.of(context).size.width to increase width of the alert
Example:
return AlertDialog(
title: Text("Select Birth Date"),
content: Container(
width: MediaQuery.of(context).size.width,
height: 300,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
initialDateTime: DateTime(1969, 1, 1),
onDateTimeChanged: (DateTime newDateTime) {
// Do something
},
),
),
actions: <Widget>[
FlatButton(
child: Text("Select"),
onPressed: () {
widget.onSelected(selectedDate);
Navigator.pop(context);
//.....
},
),
],
);
/// this works for me paste your body and see result
Future _showDialog() async {
return showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Material(
color: Colors.transparent,
child: Container(
padding: EdgeInsets.fromLTRB(5, 10, 5, 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
),
alignment: Alignment.center,
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.all(10),
/// paste your item body
child:body,
),
),
],
),
);
},
);
}
In my case, I was using listview inside the dialog box so I was not using
shrink wrap inside ListView hopes this will help someone.
ListView.builder(
shrinkWrap : true...
...
};