I try to make something like this, or this
I use
IconButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _, __) => MyPopup()));
},
to call for it, but in popup what kind of widget should return and and how to animate its appearance by pushing it from the bottom and closing it using swipe down?
You can use the bottom sheet from the Material design component which is same as this,
Guidline or example from Material Design site
Also class from official flutter doc.
Example:
void _showBottomSheet(){
showModalBottomSheet(
context: context,
builder: (builder){
return new Container(
height: 350.0,
color: Colors.transparent, //could change this to Color(0xFF737373),
child: new Container(
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(15.0),
topRight: const Radius.circular(15.0))),
child: new Center(
child: new Text("Model Sheet Example Demo"),
)),
);
}
);
}
Related
I am showing a bottomsheet in flutter by default the isDismissible = false dismissible is set to false but based on certain conditions i want to change this to true i have tried passing a bool to showModalBottomSheet method and changing its value from inside the child widget using setState method but its not working. Any help would be really appreciated.
below is my code for showing bottomsheet
openBottomDialog<T extends StateStreamableSource<Object?>>(
{required BuildContext context,
required Widget child,
double? height,
Function? onClose,
bool? dismissible,
Function? onStateChange}) {
return showModalBottomSheet(
context: context,
barrierColor: AppColors.of(context).semiTransparentBackgroundColor,
backgroundColor: AppColors.of(context).semiTransparentBackgroundColor,
isScrollControlled: true,
isDismissible: dismissible ?? false,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(24.r))),
builder: (model) {
return BlocProvider.value(
value: BlocProvider.of<T>(context),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8, sigmaY: 8),
child: Wrap(
children: [
Container(
decoration: BoxDecoration(
color: AppColors.of(context).d15151AwF5F5F5,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24.r),
topRight: Radius.circular(24.r))),
// margin: const EdgeInsets.symmetric(horizontal: 10),
child: Container(
margin: const EdgeInsets.all(8),
child: Column(
children: [
AppAsset(
key: const Key('close_bottom_sheet'),
onTap: () {
Navigator.pop(context);
onClose!();
},
asset: AppImages.line,
tintColor:
AppColors.of(context).bottomSheetHandleColor,
),
Container(child: child)
],
)),
)
],
),
));
});
}
the child widget is a state full widget and inside that i am using setState method to update this variable.
setState(() {
widget.dismissible = false;
countdownTimer.cancel();
sliderState = SlideState.loading;
});
I'am trying to show webView in a showModalBottomSheet, using inAppWebView plugin for webView. So when the webView state changes bottomSheet should adjust its height. Currently I just made a hotFix by giving scroll to bottomSheet.
return return showModalBottomSheet(
enableDrag: false,
isDismissible: false,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(20.r),
topLeft: Radius.circular(20.r),
),
),
context: context,
builder: (context) => BottomSheet(),
);
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height - (kToolbarHeight * 2),
decoration: BoxDecoration(
color: lmWhite,
borderRadius: BorderRadius.circular(20.r),
),
clipBehavior: Clip.hardEdge,
child: Stack(
children: [
InAppWebView(),
Opacity(),
],
),
);
}
Default height for bottomSheet is half the screenSize
If you want your bottomSheet to Expand according to your content use below code
showModalBottomSheet<dynamic>(
isScrollControlled: true,
context: context,
builder: (BuildContext bc) {
return Wrap(
children: <Widget>[...]
)
}
)
This will automatically expand the bottomSheet according to content inside.
I am trying to call setState inside an AlertDialog, but surprisingly setState is not changing the state variable. The variable (tasbeehChantCanAdd) i want to set from the dialog box is inside the body of the main page(outside the dialog box) This is the code for the alertDialog:
Future<void> _alertRemoveEntry(BuildContext context, String textToRemove) {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return WillPopScope(
onWillPop: (){},
child: StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(15.0),
),
),
title: const Text('Enter your info',style: TextStyle(fontWeight: FontWeight.normal,fontSize: 14),),
content: Container(
height: 150,
child: const Text("Sure to remove this?")
),
actions: <Widget>[
Container(
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
//side: BorderSide(color: Colors.red)
),
primary: Colors.purple,
),
child: Text("CANCEL"),
onPressed: () {
Navigator.of(context).pop();
},
),
Container(
width: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
//side: BorderSide(color: Colors.red)
),
primary: Colors.purple,
),
child: Text("REMOVE"),
onPressed: (){
setState((){
tasbeehChantCanAdd = "state changed";
});
ClassHub().myListSharePreference("sptasbeehAddedList", "set", tasbeehChantCanAdd, "");
Navigator.of(context).pop();
},
),
],),),
],
);
},
),
);
});
}
Please what am i doing wrong? Any help would be appreciated. Thanks
The main state class also have setState and while you are using StatefulBuilder it also has setState, being scope priority setState is coming from StatefulBuilder. You can rename it and use
child: StatefulBuilder(
builder: (context, setStateSB) {
....
setState((){ /// for state class IU update
tasbeehChantCanAdd = "state changed";
});
setStateSB((){ // update Ui inside dialog
tasbeehChantCanAdd = "state changed";
});
Try to add your AlertDialog widget inside StatefulBuilder hope its helpful to you.
Refer StatefulBuilder here
yourDropdown(BuildContext context) {
return showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, StateSetter setState) {
return AlertDialog(
);
},
);
},
);
}
Refer my answer here
Are you me from another dimension? Seriously, I just solved the same problem. I don't know if it is the recommended way of setting states on dialog, since the documentation on showDialog mentions something about states, but I solved it this way:
var choice = await showDialog(
context: context,
builder: (context) {
var list = [];
return StatefulBuilder(builder: (BuildContext context, setState) {
return AlertDialog(
[...]
);
});
});
Just put the variables you need to update through setState just before the StatefulBuilder
I am able to make bottomSheet to full height by using showModalBottomSheet(...) and set the property isScrollControlled:true.
However, the bottom sheet is over the status bar, and that is not what I expect.
Is it possible to make it below the status bar?
as an option you can modify bottom sheet
1. create new file custom_bottom_sheet.dart
2. copy-paste all code from bottom_sheet class into your custom class
3. modify buildPage() method like this
#override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
final BottomSheetThemeData sheetTheme = theme?.bottomSheetTheme ?? Theme.of(context).bottomSheetTheme;
Widget bottomSheet = SafeArea(
child: _ModalBottomSheet<T>(
route: this,
backgroundColor: backgroundColor ?? sheetTheme?.modalBackgroundColor ?? sheetTheme?.backgroundColor,
elevation: elevation ?? sheetTheme?.modalElevation ?? sheetTheme?.elevation,
shape: shape,
clipBehavior: clipBehavior,
isScrollControlled: isScrollControlled,
enableDrag: enableDrag,
),
);
if (theme != null) bottomSheet = Theme(data: theme, child: bottomSheet);
return bottomSheet;
}
use your class
import 'package:flutter/material.dart';
import 'custom_bottom_sheet.dart' as bs;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(child: Page()),
),
);
}
}
class Page extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text('show'),
onPressed: () {
bs.showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => Container(color: Colors.red),
);
},
),
);
}
}
here is modified bottom_sheet class https://pastebin.com/5U7fsqCw
also I think you need to add property
barrierColor: Colors.white.withOpacity(0),
to prevent status bar dimming
No need to create a new class. Simply assign a variable to the padding on the build of your view and use it when opening the dialog.
class MyHomeScreenState extends State<MyHomeScreen> {
double? topPadding;
#override
Widget build(BuildContext context) {
topPadding = MediaQuery.of(context).padding.top;
//...
}
showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) {
return Container(
height: MediaQuery.of(context).size.height -
topPadding!,
color: Colors.green,
);
});
If you look at SafeArea source code this is exactly what is happening. Make sure that your build is at a 'root' level on the widget tree since descendant widgets might not have a top padding because they are not underneath the edges.
Since 20 Jul 2022, you can set useSafeArea parameter to true to show modal under status bar, you can find details here.
showModalBottomSheet<void>(
useSafeArea: true, // <<<<< use this
// ....
);
Note: Now it available on master channel only, and later will be
available on stable channel.
Another easy workaround with rounded borders
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => Container(
height: MediaQuery.of(context).size.height * 0.965,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(16.0),
topRight: const Radius.circular(16.0),
),
),
child: Center(
child: Text("Your content goes here"),
),
),
);
I think this solution is the most suitable for now: (use FractionallySizedBox)
showModalBottomSheet(
context: context,
enableDrag: true,
isScrollControlled: true,
builder: (context) => FractionallySizedBox(
heightFactor: 0.9,
child: Container()
)
);
You can use the constraints parameter and set the height you want
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(35),
topRight: Radius.circular(35),
),
),
constraints: BoxConstraints(maxHeight:
MediaQuery.of(context).size.height - 50),
builder: (context) {
//continue coding..
}
The best and the easiest way is to subtract the total height of device from status bar height. You can get statusBarHeight by MediaQuery.of(context).viewPadding.top and whole device height by MediaQuery.of(context).size.height
Just like #Roddy R's answer but a little simpler
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(20))),
builder: (ctx) => Padding(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
child: YourCustomBottomSheet(),
),
),
Thanks Roddy!
showMenu<Widget>(
context: context,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
items: _buildPopupMenuItems(context));
Something like body property that expects single widget?
Is this what you're asking?
onPressed: () => showMenu(
context: context,
position: RelativeRect.fromLTRB(70.0, 450.0, 100.0, 100.0),
items: [
PopupMenuItem(
child: Text('Item'),
)
]),
Outcome