When I select a Textfield the keyboard moves over it - dart

When i select a Textfield, the keyboard is going to be shown but the keyboard hide my selected TextField. Does someone have a solution?

Scaffold(
resizeToAvoidBottomInset: true,
body: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
),
TextFormField(
decoration: InputDecoration(
labelText: 'Enter Text',
),
)
],
),
),
)
);
// resizeToAvoidBottomPadding: false isDeprecated
use resizeToAvoidBottomInset: true.

Compose an animation and move your TextField container up when a TextField gets focus.
For learning about composing animations refer to:
Composing Animations and Chaining Animations in Dart's Flutter Framework
Use Flutter's FocusNode to detect the focus on a TextField
Edit:
Here I've written an example that does exactly what you want:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Animation Demo',
theme: new ThemeData(
primaryColor: new Color(0xFFFF0000),
),
home: new FormDemo(),
);
}
}
class FormDemo extends StatefulWidget {
#override
_FormDemoState createState() => _FormDemoState();
}
class _FormDemoState extends State<FormDemo> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
FocusNode _focusNode = FocusNode();
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_animation = Tween(begin: 300.0, end: 50.0).animate(_controller)
..addListener(() {
setState(() {});
});
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
_controller.forward();
} else {
_controller.reverse();
}
});
}
#override
void dispose() {
_controller.dispose();
_focusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false, // this avoids the overflow error
appBar: AppBar(
title: Text('TextField Animation Demo'),
),
body: new InkWell( // to dismiss the keyboard when the user tabs out of the TextField
splashColor: Colors.transparent,
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
padding: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
SizedBox(height: _animation.value),
TextFormField(
decoration: InputDecoration(
labelText: 'I move!',
),
focusNode: _focusNode,
)
],
),
),
),
);
}
}

Just cut and paste your body code in this -
SingleChildScrollView(
child: Stack(
children: <Widget>[
// your body code
],
),
),

A pretty short way to realize this is by simply using a MediaQuery for getting the bottom view insets. This would look as follows:
...
return Column(
children: <Widget>[
TextField(
decoration: InputDecoration.collapsed(hintText: "Start typing ..."),
controller: _chatController,
),
SizedBox(
height: MediaQuery.of(context).viewInsets.bottom,
),
],
);
...
Hope it helps!

In my case I had to combine answer given by #Javid Noutash which uses AnimationController along with scrollPadding property of TextFormField.
code:
Add this line in build method
double bottomInsets = MediaQuery.of(context).viewInsets.bottom;
Add scrollPadding property
return ListView(
children:[
...widgets,
Container(
margin:EdgeInsets.only(
top:1.0,
left:1.0,
right:1.0,
bottom:_focusNode.hasFocus && bottomInsets != 0?
_animation.value : 1.0),
child:TextFormField(
decoration: InputDecoration(
labelText: 'I move!',
),
focusNode: _focusNode,
scrollPadding: EdgeInsets.only(bottom:bottomInsets + 40.0),
),
),
]
);
Note: Combine this code with #Javid Noutash's code

I had the same problem where the parent widget is Material and the other widgets are inside a ListView. The problem was fixed when I changed the parent widget to Scaffold without any extra code and the TextField, TextFormField in my case, is being showed above the Keyboard automatically. So, if you encountered this problem just make sure to have Scaffold as the main widget.

The most simple way is to just wrap it with
SingleChildScrollView( ... )
When the textfield is on the page bottom and the keyboard appears, the textfield is automatically scrolled up. Then the text may be entered right above the keyboard.

My way here
Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/Bg img.png'), fit: BoxFit.fill)),
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
.............
This template has some advantages:
Move content up when the keyboard appears
Column using spaceBetween inside a scroll view
Background is sticked phone scren and never change event the keyboard ups

Wrap your widget into Padding and set padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),

<activity
android:name="..ActivityName"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"/>
only for android
if you use FlutterFragment add configChanges and windowSoftInputMode for the Activity.
another way
add your TextField to a ListView
ListView(
children: <Widget>[
TextField(),
TextField(),
]
)

The above does not work if you have a CustomScrollview in a NestedScrollView.
First, you need to give the TextField a focusNode.
TextField(focusNode:_focusNode(),
...);
Use NestedScrollViewState to get access to the innerScrollController of the NestedScrollView. You can view the example here on how to get the innerScrollController. Declare a globalKey and assign it to NestedScrollView.
body: NestedScrollView(
key: globalKey,
...)
Setup the focusNode Listener to listen for when the textfield has been activated and animate the innerScrollController accordingly.
void initState() {
super.initState();
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
double innerOffSet = globalKey.currentState.innerController.offset;
if(innerOffSet < 100)
globalKey.currentState.innerController.jumpTo(innerOffSet+100);
}
});
}

var _contentController;
void _settingModalBottomSheet(BuildContext context, String initialText) {
_contentController = new TextEditingController(text: initialText);
showModalBottomSheet(
context: context,
isDismissible: true,
builder: (BuildContext bc) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: 40,
margin: EdgeInsets.only(left: 4, right: 4, bottom: 8),
decoration: BoxDecoration(
color: AppColor.bgTextFieldComment,
borderRadius: BorderRadius.circular(16),
),
child: Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 24),
child: TextField(
focusNode: _contentFocusNode,
autofocus: true,
controller: _contentController,
decoration: InputDecoration(
hintText: 'Enter Content',
border: InputBorder.none,
fillColor: AppColor.bgTextFieldComment,
),
keyboardType: TextInputType.multiline,
maxLines: null,
style: TextStyle(
color: Colors.black87,
fontSize: 16,
fontStyle: FontStyle.normal,
),
)),
),
InkWell(
child: Padding(
padding: EdgeInsets.only(left: 4, right: 4),
child: Icon(
Icons.send,
color: Colors.blue,
),
),
onTap: () {
// do ON TAP
},
),
],
),
),
SizedBox(
height: MediaQuery.of(bc).viewInsets.bottom,
),
],
);
},).then((value) {
print('Exit Modal');
});
print('request focus');
_contentFocusNode.requestFocus();
}

Instead of TextField, use TextFormField and wrap the widget with a list of TextFormField to Form:
Form(
child: Column(
children: <Widget> [
TextFormField(),
TextFormField(),
...
TextFormField(),
]
)
)

you can easily try to use Flexible widget just wrap your widget with it
Flexible(
child: Image(
image :
AssetImage('assets/logo.png'),
),
),

I had a very complex widget with Stack, Column and Single ChildChildScrollView, and I fixed it by adding a padding to the SCSV like this:
child: Stack(
children: [
Padding(
padding: const EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: SingleChildScrollView(
child: Column(
children: [... a lot of children here, one of them is a TextField],
),
),
),
// a widget at the bottom of the stack that shows despite the size of the scrollable column
],
),

It's very easy in my case check out code
Column(
children: [
Expanded(
child:// Top View,
),
postSend // edittext. and button
],
)

Related

How to set the height of FormTextField when there is prefixIcon present

I'm using the following code to generate a TextFormField which I can change the height by changing the vertical padding of the text field.
final hotelSearchField = TextFormField(
keyboardType: TextInputType.text,
focusNode: _hotelSearchFocus,
controller: _hotelSearchController,
textInputAction: TextInputAction.search,
onFieldSubmitted: (term) {},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(vertical: 7.0, horizontal: 20),
hintText: "Search",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
);
But when I add prefixIcon to the TextFormField decoration, I can't change the height of the TextFormField by changing the vertical padding.
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(vertical: 7.0, horizontal: 20),
hintText: "Search",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
prefixIcon: Icon(Icons.search, size: 20.0),
)
I tried reducing Icon size. But it only changes the size of the Icon, padding is same.
Without focus:
With focus:
I want only the height reduced.
Thank you..
prefixIcon will sure for leave some padding in TextFormField instead of that you can use the below described way where you can be able to adjust the height, width and padding of icon as well TextFormField. In the below example we take the Container and Row and divide it with the help of flex property of Expanded widget. After that we can change the height and width of icon with the help of any child widget such as Padding or SizedBox, etc., Also by using below way, we can be able to change the height and width of TextFormField with padding.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: NumericComboLineBarChart(),
);
}
}
class NumericComboLineBarChart extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MY APP'),
),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(15.0),
// padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent),
borderRadius: BorderRadius.circular(10.0),
),
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: new Container(
child: Padding(padding: EdgeInsets.only(left: 2, right: 2),
child: Icon(
Icons.search,
size: 10.0,
),)
),
flex: 1,
),
Expanded(
child: TextFormField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.search,
onFieldSubmitted: (term) {},
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(vertical: 7.0, horizontal: 0),
hintText: "Search",
border: InputBorder.none,
),
),
flex: 9,
),
],
),
)
],
),
),
);
}
}
Hope it helps :)

why my listview is not updating with setstate

here in below code i have list of widgets and used in listview iam adding widgets with list.add()in setstate also the list not updating i dont know what's happening . why my list is not updating
Here is below code
class EditorPageState extends State<EditorPage> {
List<Widget> obj = List<Widget>();
GlobalKey formkey= GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
obj.add( TextFormField(
textCapitalization: TextCapitalization.sentences,
maxLength: 50,
decoration: InputDecoration(
labelText: "TITLE",
hintText: "UR ARTICLE NAME"
),
));
obj.add(TextFormField(decoration: InputDecoration(
labelText: "Article's Propic",
hintText: "Only image Url is Accepted"
),));
return Scaffold(
appBar: AppBar(title: Text("data"),),
body: Form(
key: formkey,
child:Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 50),
child: ListView(
shrinkWrap: true,
children: obj
),
),
Container(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(),
Container(
alignment: Alignment.bottomCenter,
height: 50,width: MediaQuery.of(context).size.width,
color: Colors.black38,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(icon: Icon(Icons.format_bold),color: Colors.white,onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "heading"
),
));
});
},),
IconButton(icon: Icon(Icons.add),
onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "Start again here"
),
));
});
}
),
IconButton(icon: Icon(Icons.add_a_photo),
onPressed: (){
}
),
IconButton(icon: Icon(Icons.delete),
onPressed: (){
},
)
],
),
),
],
),
),
],
),
),
);
}
}
the above code is of statefulwidget ad it is fullscreen dialog
thats it can i know why my list is not updated
Well you will need implement a ListViewBuilder to do this and please, split your layout creation your build method isn't readable. I make some changes in your layout to be more readable and the source code has some comments to help you get what I changed. I hope it can help and also you can adapt this code to your needs.
class EditorPageState extends State<EditorPage> {
List<Widget> obj = List<Widget>();
GlobalKey formkey= GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
obj.add( TextFormField(
textCapitalization: TextCapitalization.sentences,
maxLength: 50,
decoration: InputDecoration(
labelText: "TITLE",
hintText: "UR ARTICLE NAME"
),
));
obj.add(TextFormField(decoration: InputDecoration(
labelText: "Article's Propic",
hintText: "Only image Url is Accepted"
),));
return Scaffold(
appBar: AppBar(title: Text("data"),),
//you can use this property to easily create a bottom navigation
bottomNavigationBar: _buildBottomNavigator(), // this method return BottomNavigation layout
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Form(
key: formkey,
/// here your question answer... you need implemet a listView builder
/// in every build this will create a new ListView getting itens of a especific list
child : ListView.builder(
itemCount: obj.length, // number of items in your list
//here the implementation of itemBuilder. take a look at flutter docs to see details
itemBuilder: (BuildContext context, int Itemindex){
return obj[Itemindex]; // return your widget
}),
),
),
);
}
//create your bottom navigation layout
Widget _buildBottomNavigator(){
return Container(
color: Colors.black54,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(icon: Icon(Icons.format_bold),color: Colors.white,onPressed: (){
setState(() {
obj.add(TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "heading"
),
));
});
},),
IconButton(icon: Icon(Icons.add),
onPressed: (){
print("on pressed");
setState(() {
obj.add( TextFormField(
style: TextStyle(fontWeight: FontWeight.bold),
decoration: InputDecoration(
labelText: "Start again here"
),
));
});
}
),
IconButton(icon: Icon(Icons.add_a_photo),
onPressed: (){
}
),
IconButton(icon: Icon(Icons.delete),
onPressed: (){
},
)
],
),
);
}

TextFormField disappears on click

I have form to grab info from User. But when I tap on TextFormField and keyboard shows it disappears.
https://youtu.be/UhVL2hqWOlQ
Here is my code:
class _AddInfoState extends State<AddInfo>{
static final GlobalKey<FormState> _key = new GlobalKey();
bool _validate = false;
String strTitle;
File fileImage;
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body:new Container(
child: new Form(
key: _key,
autovalidate: _validate,
child: formUI(),
),
),
);
}
Widget formUI(){
return new ListView(
children: <Widget>[
//Title Field
new Container(
padding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 0.0),
child:new TextFormField(
style: styleTextField,
keyboardType: TextInputType.text,
autofocus: true,
maxLength: 45,
decoration: InputDecoration(
hintText: 'Enter Title',
prefixIcon: Icon(
Icons.title,
size: 30.0,
color: blueColor,
)
),
validator: validateTitle,
onSaved: (String val) {
strTitle = val;
},
),
),
],
physics: new ClampingScrollPhysics(),
);
}
By my understanding from the video, since you have used a scrollable ListView inside your form, the list is scrolling upward once the keyboard appears hence it disappears.
Try setting resizeToAvoidBottomPadding: false in your Scaffold. This will make the keyboard appear as an overlay and won't push the content upward.
Example:
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
resizeToAvoidBottomPadding: false,
body:new Container(
child: new Form(
key: _key,
autovalidate: _validate,
child: formUI(),
),
),
);
}
Let me know if this helps!
Wrap the Container which has the TextFormField in a SizedBox :
new Form(
autovalidate: false,
key: _formKey,
child: new Container(
height: orientation == Orientation.portrait ? MediaQuery.of(context).size.height : MediaQuery.of(context).size.width/1.2 ,
padding: EdgeInsets.only(left: 10.0, right: 10.0),
child: new Column(
//mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new SizedBox(
width: MediaQuery.of(context).size.width,
height: 100.0,
child: new Container(
padding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 0.0),
child:new TextFormField(
style: styleTextField,
keyboardType: TextInputType.text,
autofocus: true,
maxLength: 45,
decoration: InputDecoration(
hintText: 'Enter Title',
prefixIcon: Icon(
Icons.title,
size: 30.0,
color: blueColor,
)
),
validator: validateTitle,
onSaved: (String val) {
strTitle = val;
},
),
),
)
]
)
)
]
)
)
)
Set the resizeToAvoidBottomPadding: false and then change the Column to a ListView

How to Move bottomsheet along with keyboard which has textfield(autofocused is true)?

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,
),]);
To fix this issue
All you need is to use Keyboard padding using MediaQuery.of(context).viewInsets.bottom
For more insurance, set isScrollControlled = true of the BottomSheetDialog this will allow the bottom sheet to take the full required height.
Note
If your BottomSheetModel is Column make sure you add mainAxisSize: MainAxisSize.min, otherwise the sheet will cover the whole screen.
Works with multiple TextField or TextFormField
Example
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0))),
backgroundColor: Colors.black,
context: context,
isScrollControlled: true,
builder: (context) => Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
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,
),
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.
UPDATED
Flutter 2.2 breaks the changes again!” Now you need to give bottom padding once again so the keyboard doesn't overlap the bottomsheet.
Just add:
isScrollControlled: true to showModalBottomSheet
padding: 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
});
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,
),
),
);
});
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 🙏
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>
),)),)
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
],
),
),
)
),
)
);
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(),
],
),
),
);
},
);
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
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**)
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"),
),
],
)));
},
)
Add this after the last widget of your bottom sheet
Padding(padding: EdgeInsets.only(bottom:MediaQuery.of(context).viewInsets.bottom))
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
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()
);
});
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
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>,
);
},
);
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)
Fount this on github
Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: TextField()
)
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(
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()
)
)
)
)
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
Add this in your router link modal bottom sheet
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return Messagescr();
}
);
And remove this line also in your Scaffold :
resizeToAvoidBottomInset : false,
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 61#2x.png' : widget.viewModel.leadDetail.success.lStatus == 7 ? 'assets/appimages/LeadDetail/Group 486-1.png' : 'assets/appimages/LeadDetail/Ellipse-61#3x.png',
height : widget.viewModel.leadDetail.success.lStatus == 7 ? "0" : "1",
)),
),
import 'dart:async';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import '../weight/boostrap/flutter_bootstrap.dart';
import '../weight/boostrap/bootstrap_widgets.dart';
/*
TextEditingController txtname = TextEditingController();
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
builder: (context) => SingleChildScrollView(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom),
child: new AddItem(
tektk: 'Category',
tektd: 'Add',
txtname: txtname,
ismultik:false,
onPressed: () {}),
),
);
*/
class AddItem extends StatelessWidget {
const AddItem(
{Key? key,
required this.ismultik,
required this.tektd,
required this.tektk,
required this.txtname,
required this.onPressed})
: super(key: key);
final bool ismultik;
final String tektk;
final String tektd;
final VoidCallback? onPressed;
final TextEditingController txtname;
#override
Widget build(BuildContext context) {
final MediaQueryData mediaQueryData = MediaQuery.of(context);
bootstrapGridParameters(gutterSize: 10);
return Padding(
padding: mediaQueryData.viewInsets,
child: Container(
padding: EdgeInsets.only(bottom: 90.0, left: 10.0, right: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ListTile(
trailing: SizedBox.fromSize(
size: Size(35, 35),
child: ClipOval(
child: Material(
color: Colors.indigo,
child: InkWell(
splashColor: Colors.white,
onTap: () {
Navigator.pop(context);
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.close, color: Colors.white),
],
),
),
),
),
),
),
BootstrapRow(height: 0, children: [
BootstrapCol(
sizes: 'col-md-12',
child: TextField(
style: TextStyle(color: Colors.black),
decoration: new InputDecoration(
border: new OutlineInputBorder(
borderSide: new BorderSide(color: Colors.white)),
labelText: tektk,
),
keyboardType: ismultik == true
? TextInputType.multiline
: TextInputType.text,
maxLines: null,
minLines: 1,
controller: txtname,
),
),
BootstrapCol(
sizes: 'col-md-12',
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.green, // background
onPrimary: Colors.white, // foreground
),
onPressed: onPressed,
child: Text(tektd)),
),
]),
],
),
),
);
}
}
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(...),

flutter - responsive height Form

I have this simple form, with a textarea and buttons:
When I open the keyboard, I want to decrease the size of the textarea, like a responsive layout. If I close the keyboard, the textarea should fill the remaining screen space available.
desired effect: open / active keyboard
desired effect: closed/no keyboard
My intention is to make the components fill in the screen, regardless device resolution.
Can someone provide a valida example of it? I tried several implementations and I was not able to achive the desired effect.
UPDATE:
My current code for this screen:
new MaterialPageRoute(
builder: (context) {
return new Scaffold(
resizeToAvoidBottomPadding: true,
appBar: new AppBar(
title: new Text('Add new Grocery List'),
actions: <Widget>[
new IconButton(
icon: new Icon(Icons.delete),
tooltip: 'Clear Grocery List',
onPressed: () {
this._promptRemoveGroceryBatchList();
},
),
]
),
body: new Container(
padding: const EdgeInsets.all(5.0),
child: new Form(
key: this._formGroceryBatchAdd,
child: new ListView(
children: <Widget>[
new Container(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new TextFormField(
maxLines: 10,
autofocus: true,
decoration: new InputDecoration(
labelText: 'Item List',
hintText: 'Enter a grocery list',
contentPadding: const EdgeInsets.all(16.0)
),
validator: (value) {
if (value.isEmpty) {
return 'Please enter at least one grocery item';
}
},
onSaved: (value) {
this._formBatchGroceryData = value;
},
),
new Padding(
padding: new EdgeInsets.all(8.0),
child: new Text(
'One item per line. Use ":" to specifcy the amount.\n' +
'Example:\n' +
'Potatoes:12\n' +
'Tomatoes:6',
style: new TextStyle(fontSize: 12.0, color: Colors.black54),
),
),
],
),
),
new Container(
child: new ButtonBar(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new RaisedButton(
child: new Text('Add Items'),
color: Theme.of(context).primaryColor,
textColor: Colors.white,
elevation: 4.0,
onPressed: () {
// ACTION GOES HERE
},
),
new RaisedButton(
child: new Text('Cancel'),
onPressed: () {
// ACTION GOES HERE
},
),
]
),
),
]
)
);
)
);
}
)
I'm afraid it can't be directly done using a TextField for the textarea because its size depends on the lines of text you have.
But you can simulate it by surrounding the TextField that allows unlimited lines with a Container.
This is a sample that could work for you:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Flutter Demo Home Page'),
),
body: new Column(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(),
borderRadius: BorderRadius.circular(4.0),
),
child: Padding(
padding: const EdgeInsets.only(
left: 10.0, bottom: 20.0, right: 10.0),
child: new TextField(
maxLines: null,
decoration: InputDecoration(
border: InputBorder.none,
),
),
),
),
),
),
],
),
);
}
}

Resources