How to Move bottomsheet along with keyboard which has textfield(autofocused is true)?
DartFlutterFlutter LayoutDart Problem Overview
I'm trying to make a bottomsheet that has a text field and autofocus is set to true so that the keyboard pops up. But, bottomsheet is overlapped by the keyboard. Is there a way to move bottomsheet above the keyboard?
Padding(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Column(children: <Widget>[
TextField(
autofocus: true,
decoration: InputDecoration(hintText: 'Title'),
),
TextField(
decoration: InputDecoration(hintText: 'Details!'),
keyboardType: TextInputType.multiline,
maxLines: 4,
),
TextField(
decoration: InputDecoration(hintText: 'Additional details!'),
keyboardType: TextInputType.multiline,
maxLines: 4,
),]);
Dart Solutions
Solution 1 - Dart
Add isScrollControlled = true
to BottomSheetDialog
it'll allow the bottom sheet to take the full required height which gives more insurance that TextField
is not covered by the keyboard.
Add Keyboard padding using MediaQuery.of(context).viewInsets.bottom
Note
If your BottomSheetModel
is Column
make sure you add mainAxisSize: MainAxisSize.min,
otherwise the sheet will cover the whole screen.
Example
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0))),
backgroundColor: Colors.black,
context: context,
isScrollControlled: true,
builder: (context) => Padding(
padding: const EdgeInsets.symmetric(horizontal:18 ),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Text('Enter your address',
style: TextStyles.textBody2),
),
SizedBox(
height: 8.0,
),
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: TextField(
decoration: InputDecoration(
hintText: 'adddrss'
),
autofocus: true,
controller: _newMediaLinkAddressController,
),
),
SizedBox(height: 10),
],
),
));
Please note that:
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0))),
It's not required. It's just that I'm creating a rounded bottom sheet.
padding: MediaQuery.of(context).viewInsets
UPDATED Flutter 2.2 breaks the changes again!” Now you need to give bottom padding once again so keyboard don't overlaps bottomsheet.
Solution 2 - Dart
Just add:
isScrollControlled: true
to showModalBottomSheetpadding: MediaQuery.of(context).viewInsets
to widget in builder- column/wrap both works
showModalBottomSheet<void>(
isScrollControlled: true,
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30.0),
topRight: Radius.circular(30.0)),
),
builder: (BuildContext context) {
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: Container(
child: Wrap(
children: <Widget>[
TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter a search term'),
),
TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter a search term'),
),
TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter a search term'),
),
TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter a search term'),
)
],
)));
},
);
Update Feb 25 2020 better solution
showModalBottomSheet(
isScrollControlled: true,
builder: (BuildContext context) {
return SingleChildScrollView(
child: Container(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 0.0), // content padding
child: Form(...)) // From with TextField inside
});
Solution 3 - Dart
In Order to focus on the Keyboard in BottomSheet
- Wrap TextField
in Padding Widget as like Below e.g Code:
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: TextField(
autofocus: true,
),
),
);
});
Solution 4 - Dart
In the latest version of flutter, you can move your bottomSheet using isScrollControlled
property/named parameter. Suppose i have a function(_showModal) which will invoke when a button is pressed. And i define the bottom sheet functionality on that function.
void _showModal() {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return Column(
children: <Widget>[
TextField(// your other code),
SizedBox(height: 5.0),
TextField(// your other code),
SizedBox(height: 5.0),
TextField(// your other code),
]
);
},
);
}
Here a ModalBottomSheet will appear but with fullscreen of height. And you don't need that height. So, you need to Column's mainAxisSize
to min
.
Column(
mainAxisSize: MainAxisSize.min,
// your other code
)
Fullscreen of height problem is solved, but ModalBottomSheet doesn't move to top when keyboard is appeared. Ok, to solve this issue you need to set viewInsets
bottom padding to your ModalBottomSheet. So to set padding we need to wrap our Column with Container or Padding and then set the padding. The final code will look like this
void _showModal() {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return Container(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
// You can wrap this Column with Padding of 8.0 for better design
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(// your other code),
SizedBox(height: 5.0),
TextField(// your other code),
SizedBox(height: 5.0),
TextField(// your other code),
]
),
);
},
);
}
Hope your issue is fixed. Thank's
Solution 5 - Dart
Try this
My Solution is
- Use
isScrollControlled: true
- Add Padding
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom)
- Wrap your layout in
SingleChildScrollView
SAMPLE CODE
Future<void> future = showModalBottomSheet(
context: context,
isDismissible: true,
isScrollControlled: true,
backgroundColor: Colors.white.withOpacity(0.2),
builder: (context) => SingleChildScrollView(
child: GestureDetector(
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom
),
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
children: <Widget>[
// add your widget here
],
),
),
)
),
)
);
Solution 6 - Dart
Package: https://pub.dev/packages/modal_bottom_sheet
Wrap your widget into Padding and set padding like this ==>
padding: MediaQuery.of(context).viewInsets // viewInsets will decorate your screen
You can use showMaterialModalBottomSheet or showModalBottomSheet or showCupertinoModalBottomSheet
showModalBottomSheet(
context: context,
barrierColor: popupBackground,
isScrollControlled: true, // only work on showModalBottomSheet function
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(borderRadiusMedium),
topRight: Radius.circular(borderRadiusMedium))),
builder: (context) => Padding(
padding: MediaQuery.of(context).viewInsets,
child: Container(
height: 400, //height or you can use Get.width-100 to set height
child: <Your Widget here>
),)),)
Solution 7 - Dart
I got it fixed by increasing the height of the child widget when the keyboard gets opened. initially value of MediaQuery.of(context).viewInsets.bottom will be 0 it will change when the keyboard gets focused.
showModalBottomSheet<void>(
enableDrag: true,
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return Card(
color: Colors.white,
child: Container(
height: MediaQuery.of(context).size.height / 2 +
MediaQuery.of(context).viewInsets.bottom,
child: Column(
children: <Widget>[
TextField(),
TextField(),
],
),
),
);
},
);
Solution 8 - Dart
UPDATED 2021 May flutter 2.2! Now you need to give bottom padding. The below written was a bug.
UPDATED 2020!
This answer is true, but you don't have to give bottom padding now! Find and delete this line:
padding: MediaQuery.of(context).viewInsets
Solution 9 - Dart
For people who can't solve their problem trying all the answers. These answers are correct but not so clear.
When using
MediaQuery.of(context).viewInsets.bottom)
make sure your context variable is using the one provided by bottom sheet builder property.
builder :(**c**)=>MediaQuery.of(**c**)
Solution 10 - Dart
Try this.
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) {
return AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
duration: const Duration(milliseconds: 100),
curve: Curves.decelerate,
child: Container(
child: Wrap(
children: [
TextField(
decoration: InputDecoration(labelText: "1"),
),
TextField(
decoration: InputDecoration(labelText: "2"),
),
TextField(
decoration: InputDecoration(labelText: "3"),
),
],
)));
},
)
Solution 11 - Dart
If you have full screen or fixed size showModalBottomSheet
don't use padding
it will not solve your problem. Use margin
instead of padding
like this :
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
marign: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: TextField()
);
});
Solution 12 - Dart
You should to use this then,
showModalBottomSheet(
isScrollControlled: true,
context: context,
shape: RoundedRectangleBorder(
// <-- for border radius
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0),
),
),
builder: (BuildContext context) {
return SingleChildScrollView(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: drunkenWidget()...
//BTW, Never ever Drink
Solution 13 - Dart
Add this after the last widget of your bottom sheet
Padding(padding: EdgeInsets.only(bottom:MediaQuery.of(context).viewInsets.bottom))
Solution 14 - Dart
After combining different solutions I got this:
if you don't want it to be Full screen and don't want to use the Padding workaround use
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
enableDrag: true,
isDismissible: true,
useRootNavigator: true,
builder: (BuildContext ctx) {
return Scaffold( // use CupertinoPageScaffold for iOS
backgroundColor: Colors.transparent,
resizeToAvoidBottomInset: true, // important
body: SingleChildScrollView(
child: Form(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextFormField(),
TextFormField(),
],
),
),
),
),
);
},
);
on Flutter (Channel master, v1.15.3-pre.37, on Mac OS X 10.15.2 19C57, locale en-US)
Solution 15 - Dart
Instead of using builder: (BuildContext context) { }
in the builder, use builder: (context) { }
With this solution my modal bottom sheet sticks to the statusbar (acts like Scaffold
with resizeToAvoidBottomInset: false
) and allows to view all the form fields and scroll through the form if it is still needed to view bottom text fields.
For more details, here's the link from where I found the solution- https://github.com/flutter/flutter/issues/18564#issuecomment-602604778
Solution 16 - Dart
Fount this on github
Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: TextField()
)
Solution 17 - Dart
Wrap the Form
with a Scaffold
widget, and then wrap the TextFormField
with a SingleChildScrollView
:
return Container(
height: screenHeight * .66,
child: Scaffold(
body: Form(
key: _form,
child: SingleChildScrollView(
child:TextFormField()
)
)
)
)
Solution 18 - Dart
showModalBottomSheet(
isScrollControlled: true,
builder: (BuildContext context) {
return SingleChildScrollView(
child: Container(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Padding(
padding: const EdgeInsets.all(15.0), // content padding
child: Container())});
Note : This line does all the magic
Solution 19 - Dart
If you still have not found your issue. So I think you have missed in your BuilderContext. Sometimes when you implement modalBottomSheet it will give you only the context parameter. So add context with BuildContext.
builder: (BuildContext context) { //-Here is your issue add BuilderContext class name as it as
return Padding(
padding: MediaQuery.of(context).viewInsets,
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: new Container(
Solution 20 - Dart
Simple Solution, you can customize this :
Container(
margin: EdgeInsets.only(left: 15),
child: InkWell(
onTap: () {
showModalBottomSheet(
isScrollControlled : true,
context: context,
backgroundColor: Colors.transparent,
builder: (context) {
return Container(
padding: EdgeInsets.only(top: 15, left: 15, right: 15, bottom: 10),
width: double.infinity,
decoration: BoxDecoration(
color: AppTheme.leadItemColor1,
borderRadius: BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)),
),
child: Column(
children: [
_assignTo(widget.viewModel, context),
SizedBox(height: 12,),
txtComment(widget.viewModel),
SizedBox(height: 12,),
CRMButton(
title: 'Select',
onTap: () async {
Navigator.pop(context);
await widget.viewModel.updateStatus(7, why: "${ConstantData.lostOptions[_selectedNumber]}");
},
)
],
),
);
},
);
},
child: CustomTabBarItem1(
image: widget.viewModel.leadDetail.success.lStatus == 7 ? 'assets/appimages/LeadDetail/icons-03-01.png' : 'assets/appimages/LeadDetail/icons-04-01.png',
bottomTitle: 'Lost',
topTitle: widget.viewModel.leadDetail.success.lStatus > 7 ? 'assets/appimages/LeadDetail/Ellipse [email protected]' : widget.viewModel.leadDetail.success.lStatus == 7 ? 'assets/appimages/LeadDetail/Group 486-1.png' : 'assets/appimages/LeadDetail/[email protected]',
height : widget.viewModel.leadDetail.success.lStatus == 7 ? "0" : "1",
)),
),
Solution 21 - Dart
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
context: context,
isScrollControlled: true,
builder: (builder) {
return Container(
height: MediaQuery.of(context).size.height - 40,
padding: MediaQuery.of(context).viewInsets,
child: <Your Widget Here>,
);
},
);
Solution 22 - Dart
Just add
if (_isEditing) SizedBox(height: MediaQuery.of(context).viewInsets.bottom),
under the keyboard and hide all other content below the textfield with
if (!_isEditing) Widget(...),