White Box Obscures View When Keyboard Appears - flutter

For some reason after updating flutter, one of the sections of my app has been broken. I have a list of text form widgets set in a SingleChildScrollView. Whenever I press one of the text forms, the keyboard appears and an empty white box pushes itself up into the field of view, obscuring the text entry boxes.
After having some trouble with text entry in a list view before I followed the advice of this link: https://www.didierboelens.com/2018/04/hint-4-ensure-a-textfield-or-textformfield-is-visible-in-the-viewport-when-has-the-focus/
It effectively solved the problems I had beforehand where the text entry boxes were not remaining visible when the keyboard appears. But now the while box is appearing and obscuring the view. I also made sure to use:
resizeToAvoidBottomPadding: false
as is regularly advised.
Here is the code in question with one of the text field widget's code too:
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new SafeArea(
child: new Form(
key: _formKey,
child: new SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
circumstances(),
divider(),
description(),
divider(),
externalHappenings(),
divider(),
internalHappenings(),
divider(),
reflectionsAndCorrections(),
divider(),
abatement(),
divider(),
footerButtons()
],
),
)
)
),
resizeToAvoidBottomPadding: false,
);
}
Widget circumstances() {
return new EnsureVisibleWhenFocused(
focusNode: _focusNodeCircumstances,
child: new TextFormField(
controller: _circumstancesController,
maxLines: maxLines,
decoration: const InputDecoration(
border: const OutlineInputBorder(
borderRadius: const BorderRadius.all(const Radius.circular(0.0)),
borderSide: const BorderSide(color: Colors.black, width: 1.0)
),
filled: true,
labelText: "Circumstances",
hintText: "Who was there? Where were you?",
),
autofocus: true,
validator: (value) {
_activeJournalEntry.setCircumstances(value);
if(value == null || value.isEmpty) {
return "Please enter some circumstances.";
}
},
focusNode: _focusNodeCircumstances,
),
);
}

The replies to this thread pointed me in the right direction to solve the issue.
I had three deep nested scaffolds where the innermost two had this set:
resizeToAvoidBottomPadding: false
However, my outermost Scaffold did not, causing this issue. So it turns out that it is fine to have nested Scaffolds but you must ensure that each of them have that property set to avoid this issue.
See also,
https://github.com/flutter/flutter/issues/7036

As jared-nelsen stated, one of your Scaffold does not have the property specified. Note that this can also be caused by an external library, in my case it was the DevicePreview library.

Related

TextFormField retrieves the focus and reassigns the initial value when the keyboard is closed

I find myself working with TextFormField hand in hand with DropdownButton. There is a strange process going on inside the view. I put the steps below:
To the TexFormField, I'm assigning an initial value: controller: _nameController..text = datumAdministrative.name.
I enter a new value to the TextFormField.
When the DropdownButton is deployed, the keyboard is closed the whole Widget is redrawn, which causes the TextFormField to recover its initial value and does not keep the new value entered.
Is there any way to avoid, that the TextFormField returns to its initial value when selecting DropdownButton? I would appreciate if you could help me with a post or feedback.
Code Scaffold:
return Scaffold(
resizeToAvoidBottomPadding: false,
resizeToAvoidBottomInset: true,
appBar: AppBar(
backgroundColor: ColorsTheme.primary,
leading: GestureDetector(
onTap: () {
Navigator.pushReplacementNamed(context, 'administrativeListData');
},
child: Container(
padding: EdgeInsets.all(16),
child: FaIcon(FontAwesomeIcons.arrowLeft)),
),
centerTitle: true,
title: Text(datumAdministrative.name +
' ' +
datumAdministrative.lastNameFather),
automaticallyImplyLeading: false),
body: Stack(
children: <Widget>[
ImageBackground(),
_sizeBoxHeight(),
Container(
child: Form(
key: formValidator.formKey,
child: ListView(
children: <Widget>[
_containerImageUser(context, datumAdministrative),
_sizeBoxHeight(),
CustomCardExpansionTile(
title: Constants.administrativeData,
icon: FontAwesomeIcons.addressBook,
widget: Container(
padding: EdgeInsets.all(15),
child: responsiveDataAdministrative(context)),
),
CustomCardExpansionTile(
title: Constants.addressInformationAdministrative,
icon: FontAwesomeIcons.houseUser,
widget: Container(
padding: EdgeInsets.all(15),
child: responsiveAddressInformationAdministrative(
context))),
CustomCardExpansionTile(
title: Constants.userDataSystem,
icon: FontAwesomeIcons.idCard,
widget: Container(
padding: EdgeInsets.all(15),
child: responsiveInformationSystemAdministrative(
context))),
],
),
),
),
],
),
);
Code TextFormField:
TextFormField(
controller: _nameController..text = datumAdministrative.name,
keyboardType: TextInputType.text,
textInputAction: null,
textCapitalization: TextCapitalization.sentences,
onChanged: (value) => formValidator.name = value,
validator: (value) {
if (formValidator.fieldValidText(value)) {
return null;
} else {
return Constants.nameAdministrativeMessage;
}
});
I see that you set the value for the text property of TextEditingController inside the build method. So, it will be invoked whenever the widget rebuilds, causing the value for the field back to the initial one.
The docs actually tells about it:
text property
Setting this will notify all the listeners of this
TextEditingController that they need to update (it calls
notifyListeners). For this reason, this value should only be set
between frames, e.g. in response to user actions, not during the
build, layout, or paint phases.
To fix it, you should remove the cascade notation here:
controller: _nameController..text = datumAdministrative.name,
Do it inside initState() instead:
#override
void initState() {
_nameController.text = datumAdministrative.name;
}

How to add a CircleAvatar to a Flutter TextField?

Trying to create a post screen, where the user can select an image and post a text.
The main problem that I have is that I need to add a Cirlce avatar for the user on the left side of the textField and a hint "Insert your text here"
this is what I achieved so far:
class CityRecommendations extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(100),
child: DropdownAppBar(),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
TextField(
decoration: InputDecoration(
hintText: "Insert your message",
),
scrollPadding: EdgeInsets.all(20.0),
autofocus: true,
),
MessageBox(),
],
),
);
}
}
How to add a circleAvatar for the user?
I do not sure this is you wanted
Row(
children: <Widget>[
CircleAvatar(child: Icon(Icons.person)),
Expanded(
child: Padding(
padding: EdgeInsets.all(8),
child: TextField(
decoration: InputDecoration(
hintText: "Insert your message",
),
scrollPadding: EdgeInsets.all(20.0),
autofocus: true,
),
))
],
),
You can use CircleAvatar widget for that.
A circle that represents a user.
Typically used with a user's profile image, or, in the absence of such an image, the user's initials. A given user's initials should always be paired with the same background color, for consistency.
If foregroundImage fails then backgroundImage is used. If backgroundImage fails too, backgroundColor is used.
The onBackgroundImageError parameter must be null if the backgroundImage is null. The onForegroundImageError parameter must be null if the foregroundImage is null.
You can wrap your TextField with CircleAvater

getSelectedText on inactive InputConnection flutter

I have this weird problem,When i try to enter value to textfield the keyboard comes up when i try to type the the keyboard goes away , i am also doing fill up Username,Place,mobile that i fetching from sharedprefrence and it's working,but when i try to enter age,height,weight keyboard comes up & goes with in seconds,this is the error/warning i am getting,there is no problem in flutter doctor,
W/IInputConnectionWrapper(23904): getSelectedText on inactive InputConnection
W/IInputConnectionWrapper(23904): getTextAfterCursor on inactive InputConnection
W/IInputConnectionWrapper( 8756): beginBatchEdit on inactive InputConnection
W/IInputConnectionWrapper( 8756): endBatchEdit on inactive InputConnection
Code & View
class RegistrationScreenState extends State<RegistrationScreen> {
TextEditingController mobile = TextEditingController();
TextEditingController Username = TextEditingController();
TextEditingController Place = TextEditingController();
TextEditingController age = TextEditingController();
TextEditingController height = TextEditingController();
TextEditingController weight = TextEditingController();
void initState() {
getDetails();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery
.of(context)
.size;
return Scaffold(
appBar: AppBar(
title: Text("Registration", style: TextStyle(color: Colors.black)),
backgroundColor: Colors.orange,
),
body: SingleChildScrollView(
child: Stack(
children: [
Column(
children: [
Container(
child: Image.asset('assets/images/gym.png',
height: 150,
width: double.infinity,
fit: BoxFit.fitWidth),
),
SizedBox(
height: 50,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: Username,
decoration: InputDecoration(
prefixIcon: Icon(Icons.perm_identity),
),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: mobile,
decoration: InputDecoration(
prefixIcon: Icon(Icons.mobile_screen_share),
),
),
),
),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"User Information",
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.bold),
)),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: Place,
decoration: InputDecoration(),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: age,
decoration: InputDecoration(
hintText: 'Age',
),
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: height,
decoration: InputDecoration(
hintText: 'Height(in cm)',
),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: weight,
decoration: InputDecoration(
hintText: 'Weight(in kg)',
),
),
),
),
],
),
],
),
],
),
),
);
}
// get & fill Shareprefrece data to textfield
getDetails() async {
Future user = SharedPrefrence().getUserMobile();
Future name = SharedPrefrence().getUserName();
Future place = SharedPrefrence().getUserPlace();
user.then((data) async {
var mobile_no = data;
setState(() {
if (mobile_no.isNotEmpty) {
mobile.text = mobile_no;
}
else
{
mobile.text = "";
}
});
});
name.then((data) async {
var user_name = data;
setState(() {
if (user_name.isNotEmpty) {
Username.text = user_name;
}
});
});
place.then((data) async {
var user_place = data;
setState(() {
if (user_place.isNotEmpty) {
Place.text = user_place;
}
});
});
}
}
I am not sure that if this will help you but I was also facing the same issue.
I was getting this error when I was using the TextFormField with in Form and the issue was that I created the global form key with in the build method.
class _AddTaskState extends State<AddTask> {
final _formKey = GlobalKey<FormState>(); // <-
String name;
String description;
#override
Widget build(BuildContext context) {
// first I was using that here.
return Scaffold(
In my case I had TextFeild in AnimatedSwitcher. The problem was i had key: UniqueKey() inside my widget that containes the TextFeild. So When ever i touched the text feid UniqueKey() gets called and then the widget tree gets regernated.
If you are using form validator, move your form key out of your build context. This should solve your issue.
Instead of -
class SingInScreen extends StatelessWidget {
final _sigInFormKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
Size size = getRelativeSize(context);
Use this-
`final _sigInFormKey = GlobalKey<FormState>();
class SingInScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
Size size = getRelativeSize(context);`
Known issue, tracked here,it's still there. There is no explanation on what's causing it.
I did a little bit of digging. It looks like Android is generating these warnings because we are holding the InputConnection incorrectly in the Engine's TextInputPlugin. I haven't really figured out what we're doing wrong, though.
source
I was also getting the same issue when tapping on the TextField.
Use auto focus = true, and issue will be resolved.
TextField( autofocus: true, );
I "forced" the formatting, in my case for example my form controller was an integer so I did it :
TextFormField(
controller: _formTextControllers.mycontroller,
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'label',
),
inputFormatters: [
**FilteringTextInputFormatter.digitsOnly,**
MyInputFormatter(),
],
),
Try using the textfield methods like onChanged, onSubmitted,...
Also try using focus nodes.
Use
FocusScope.of(context).requestFocus(FocusNode());
I've been scratching my head over the same issue.
The thing that resolved it for me was removing the media query from within the build method. I guess calling the keyboard messes with this if its running inside the build method and funny things happen.
Size size = MediaQuery
.of(context)
.size;
Try doing without it, or passing it into the widget as a static property above the build method
So okay I have found a solution for this in my use case.
My keyboard used to disappear as soon as it appeared on my screen. This not the bug in the framework, let us understand what happens in the background.
When the keyboard pops up, the screen needs to rebuild its components accordingly, so it forces a rebuild. Therefore the entire widgets are re-rendered including the TextFormField or TextField, which closes the Keyboard.
To solve this problem, we have to find a way to uniquely identify our widget which is rebuilding, and stop flutter from recreating that widget.
This can be done by using keys, first find the parent widget under which our TextFormField/TextField falls, and provide a unique key to it. Remember NOT to initialize the key on the key parameter of the widget. Instead declare it outside the build method and then use it. This makes sure that the unique does not change every time the build method is called.
I hope that this helps.
Thank You!
In my case, I had this problem while my array of TextFormFields were children of DataCells of a DataTable which this DataTable was itself child of a ExpansionPanel widget.
The problem got fixed when I replaced the parent ExpansionPanelList with a Column and removed the ExpansionPanel widget.
I thought that explaining my own case might help somebody with similar issues.
In my case, I was using a global navigation key for navigation. when I was on an inner page the moment I touch Textfeild or TextFormFeild it pop to the navigation initial root, the problem that cause this problem was I declared the Navigation module inside a Stateless widget. When I changed it to stateful the issue is solved.

How to fix "BoxConstraints forces an infinite width" and how to delete an item from a list?

I am a beginner in Flutter and I can not get the result I want because I have a "layout problem". I tried several things for hours...
Technical problem:
When I click on "add player button" to add a new TextField to set more play name, I have an error: "BoxConstraints forces an infinite width". So, the TextField isn't displayed.
Other features that I do not know how to realize:
- I have a "dropdownmenu' to choose difficulty game. Why the default text isn't displayed (Difficulty: normal)?
- How to do this: When the user clicks on the icon "remove" (see suffixIcon on TextField), then the corresponding fieldText is deleted?
- How to do this: When user click to add player the default HintText is incremented (Player 2, Player 3, Player 4, ....)?
- Why my background gradient doesn't fix when user scroll page? (like in HTML/CSS 'background-attachment: fixed') ?
import 'package:flutter/material.dart';
/// Styles
///
class Homepage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<Homepage> {
String dropdownValue = 'Normal';
List<TextField> _playerList = new List(); //_playerList is my List name
int playerListIndex = 0; //Count the number of times "Add" button clicked
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: <Widget>[
// To have a gradient background
new Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(
gradient: new LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.1, 1],
colors: [
Colors.redAccent[200],
Colors.red[300],
],
tileMode:
TileMode.repeated,
),
),
//I need SingleChildScrollView to haven't "Overflow yellow bar on bottom screen"
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
// Box to add big image
SizedBox(
height: 450,
),
// DROP DOWN MENU to choose difficulty modes
InputDecorator(
decoration: InputDecoration(
prefixIcon: const Icon(Icons.games),
filled: true,
),
child: DropdownButtonHideUnderline(
child: new DropdownButton<String>(
value: dropdownValue,
hint: Text('Difficulty normal'),
isDense: true,
items: <String>['Normal', 'Easy', 'Hard']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
),
),
),
//Field player name 1. At least I need 1 player
new TextField(
maxLength: 20,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.person),
filled: true,
hintText:"Player 1",
counterText: "",
),
),
//Field for other player name 2, 3, 4, ...
new ListView.builder(
padding: EdgeInsets.all(0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: _playerList.length,
itemBuilder: (context, index) {
TextField widget = _playerList.elementAt(index);
return widget;
}),
//Button to add other field text to set player name. The user can delete a player on click on "clear icon button"
new Align(
alignment: Alignment.centerRight,
child: FlatButton.icon(
color: Colors.black,
icon: Icon(
Icons.add,
color: Colors.white,
size: 18,
),
label: Text('Add player',
style:
TextStyle(fontSize: 12, color: Colors.white)),
onPressed: () {
setState(() {
playerListIndex++;
_playerList.add(
new TextField(
maxLength: 20,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.person),
suffixIcon: new IconButton(
icon: Icon(Icons.clear),
onPressed: () {
_playerList.removeAt(playerListIndex); //Doesn't work
}),
filled: true,
hintText: "Player $playerListIndex", //Doesn't work i would like Player 2, Player 3, ...
counterText: "",
),
),
);
print(playerListIndex);
print(_playerList);
print(_playerList[0]);
});
}),
),
new ButtonTheme(
minWidth: 350,
height: 45,
child: FlatButton(
color: Colors.black,
child: Text('Play',
style:
TextStyle(fontSize: 18, color: Colors.white)),
onPressed: () {
// Perform some action
},
),
),
],
),
),
),
),
),
]),
);
}
}
I think that I understood what's going on. Let's begin:
First. Your TextField is not showing up and you're getting an error because you didn't set a width and a height for it, so, it's trying to get the maximum size as it can get. Solution for this? Wrap it in a Container widget (or SizedBox) and give it a width and a height. That should fix the first problem.
Second. Your DropDownMenu's hint text (Difficulty Normal) is not showing because you're not passing the parameter "hint" in the DropDown widget, See the hint propierty below.
Third. You want to clear the TextField string when click on a suffix, right? To achieve this, pass a GestureDetector or an IconButton as your suffix component, create a TextEditingController and pass it in the TextField, in the controller section, then, on the onPressed/onTap method (depending on which Widget you'll set) set this: _textController.text.clear() method, inside the setState function. This should fix the problem.
Forth. You want the list of player's string to increase as you add more players right? You have many ways to achieve this, one of them is creating an empty list, you can mock to test it, and then, everytime you click the "Add player" button, you'll add a String corresponding to the value inside a for loop passing the for's index as int value in the "Player $index". Again, the for method will receive a setState method, and inside the setState, your logic to add one more Player.
And finally, your gradient does not keep fixed? Hmm, I think you can pass a proprierty in the Scaffold widget called resizeToAvoidBottomInset and set it to false.
If something did not work as you expected, reply it and I'll help you out.

Flutter: textAlign:TextAlign.end dosen't work in TextField/TextFormField

I have simple TextField inside a row with a Text and a TextField but it gives issue mentioned below if textAlign:TextAlign.end is used in TextField/TextFormField. Though textAlign:TextAlign.start and textAlign:TextAlign.center works fine.
When user types some thing for example "Hello World" and brings the cursor to the middle for example letter "o" of word "Hello" manually by tapping and presses the backspace key of android keyboard, the "Hello" word gets deleted but now cursor moves to end of the word i.e. at letter "d" of "World" but now if user press backspace it won't get deleted. Seems like the caret moves outside the input box.
Link to full code and a video
Widget build(BuildContext context) {
return MaterialApp(
home:Scaffold(
appBar: AppBar(title: Text("Demo")),
body: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Text("data"),
flex: 2,
),
Expanded(
flex: 2,
child: TextField(
decoration: InputDecoration(
hintText: "Enter Text Here",
border: InputBorder.none
),
textAlign: TextAlign.end,
controller: TextEditingController(text: "Text"),
)
)
]
),
]
),
)
);
}
My specific issue is resolved by Flutter, as of now only on DEV channel and is being tracked by issue.