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.
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;
});
Safearea() does not wrap the showModalBottomSheet properly. I need to show the modal under the status bar.
class ModalBottomSheet {
static void renderModalBottomSheet(BuildContext context, Widget widget) {
showModalBottomSheet(
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(border2),
),
),
context: context,
builder: (BuildContext context) {
return SafeArea(
child: Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: widget,
),
);
},
);
}
}
I have tried the following solutions but it still doesn't work properly
MediaQuery.of(context).padding.top
MediaQueryData.fromWindow(WidgetsBinding.instance.window).padding.top
Update:
I managed to solve it this way.
add this to the bottomsheet
backgroundColor: Colors.transparent,
and padding top
top: MediaQuery.of(context).padding.top,
full code:
class ModalBottomSheet {
static void renderModalBottomSheet(BuildContext context, Widget widget) {
showModalBottomSheet(
isScrollControlled: true,
backgroundColor: Colors.transparent,
context: context,
builder: (_) {
return SafeArea(
child: Padding(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: widget,
),
);
},
);
}
}
your child widget can have the border radius and colors instead.
open keyboard
closed keyboard
Try this. If it doesn't work, refer this page
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[...
you should get MediaQuery.of(context).viewPadding.top before showModalBottomSheet and pass it to sheet inside, then use EdgeInsets.top inside the sheet.
I am trying to implement a function to enable AlertDialog scrollable when the keyboard is displayed. In order to achieve it, I used CustomScrollView as follow. However, I could not close the popup window by clicking outside of it,
await showDialog<void>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return CustomScrollView(slivers: <Widget>[
SliverFillRemaining(
hasScrollBody: true,
child: AlertDialog(
title: Text('hello'),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
)))
]);
});
Before adding CustomScrollView, the barrierDismissible works find as follow:
await showDialog<void>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
title: Text('hello'),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
));
});
Can anyone please help how to enable the whole dialog scrollable when keyboard is shown? Thank you
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!
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"),
)),
);
}
);
}