I have a problem when show an alert dialog. My AlertDialog too tall (many TextFields). When I click any below TextFields, keyboard makes dialog short and SingleChildScrollView (I wrap my content in it) does not scroll to the TextField which has focus. However, when I type a character on that textfield, SingleChildScrollView works fine, scrolls to that TextField automatically. So, how do SingleChildScrollView scrolls to a TextField when user click in the first time (has focus).
p/s: I tried add a listener into FocusNode, but it does not work.
For example: I will click 'Fullname' field (picture 1) and the keyboard makes dialog short and I can not see the 'Fullname' field (picture 2). When I type a character, the scrollview scroll to that correctly (picture 3).
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(
'Dialog Title',
textAlign: TextAlign.center,
),
titleTextStyle: TextStyle(
fontSize: 16.0,
color: Theme.of(context).textTheme.title.color,
fontWeight: FontWeight.w800,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'.toUpperCase()),
),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'.toUpperCase()),
),
],
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
focusNode: _nodePhone,
maxLength: 10,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: 'Phone number',
),
textInputAction: TextInputAction.next,
onEditingComplete: () {
FocusScope.of(context).requestFocus(_nodeEmail);
},
),
TextField(
focusNode: _nodeEmail,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
),
textInputAction: TextInputAction.next,
onEditingComplete: () {
FocusScope.of(context).requestFocus(_nodeFullname);
},
),
TextField(
focusNode: _nodeFullname,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Fullname',
),
textInputAction: TextInputAction.next,
onEditingComplete: () {
FocusScope.of(context).requestFocus(_nodePassword);
},
),
TextField(
focusNode: _nodePassword,
obscureText: true,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Password',
),
textInputAction: TextInputAction.done,
),
],
),
),
);
}
I also have this problem, I manage to solve it by give a controller to SingleChildScrollView then when onTap on TextField. Await for few millisecond for dialog to collapse then scroll to the end of dialog
Here is some sample code
//declare first
ScrollController _scrollController = ScrollController();
//your field code
SingleChildScrollView(
// give a controller
controller: _scrollController,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: < Widget > [
TextField(
focusNode: _nodePhone,
maxLength: 10,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: 'Phone number',
),
textInputAction: TextInputAction.next,
onEditingComplete: () {
FocusScope.of(context).requestFocus(_nodeEmail);
},
),
//suppose this is your very last textfield
TextField(
focusNode: _nodeEmail,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
),
textInputAction: TextInputAction.next,
onEditingComplete: () {
FocusScope.of(context).requestFocus(_nodeFullname);
},
onTap: () {
Future.delayed(Duration(milliseconds: 500), () {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 200),
curve: Curves.ease);
});
},
),
]
)
);
Related
I have this code displaying 2 ListTiles in the same line:
Row(
children: <Widget>[
Flexible(
child: ListTile(
leading: Icon(Icons.call),
title: TextFormField(
controller: _phoneNumberController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
hintText: translate('contact_list.number')),
validator: (value) {
return Helpers.checkInput(value);
},
),
),
),
Expanded(
child: ListTile(
title: TextFormField(
controller: _phoneNumberController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
hintText: translate('contact_list.number')),
validator: (value) {
return Helpers.checkInput(value);
},
),
),
),
],
),
Both of them are taking 50% of the space but I'd need the first one taking a fixed width.
What I'm trying to archive is display a telephone number input with its phone code on the left (and that needs to be smaller)
This could be a possible solution for what you are looking for:
Row(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
/// Just an example, but this makes sure, that since you set a fixed width like 300.0, on small screens this won't get too big. For example by setting a maxWidth constraint like this, its width will be 300.0, but at max as big as 1 / 3 of the screen width so it gets smaller on small screen sizes
maxWidth: MediaQuery.of(context).size.width / 3,
),
child: SizedBox(
/// Enter your fixed width here, 300.0 ist just an example
width: 300.0,
child: ListTile(
leading: Icon(Icons.call),
title: TextFormField(
controller: _phoneNumberController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
hintText: translate('contact_list.number')),
validator: (value) {
return Helpers.checkInput(value);
},
),
),
),
),
Expanded(
child: ListTile(
title: TextFormField(
controller: _phoneNumberController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
hintText: translate('contact_list.number')),
validator: (value) {
return Helpers.checkInput(value);
},
),
),
),
],
),
Here is my code for the text field inside my scaffold:
child: TextField(
obscureText: _obscureText,
controller: myController2,
focusNode: myFocusNode2,
textInputAction: TextInputAction.done,
onSubmitted: (value){
myFocusNode2.unfocus();
_loginMethod();
},
decoration: InputDecoration(
labelText: "Password",
border: OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(_obscureText ? Icons.visibility_off: Icons.visibility),
onPressed: (){
setState(() {
_obscureText = !_obscureText;
});
Timer.run(() => myFocusNode2.unfocus());
},
)
),
),
What I have right now works, but it is not clean at all. Most of the time the text field becomes focused for a second then the .unfocus() unfocuses it after a delay, so I get this jump effect with the keyboard popping up and then going back down. Only a few times the text field will never get focused at all and I don't understand why.
Is there a way to make sure the IconButton never focuses the text field when it is pressed?
I just can think of 3 solutions, not prefect but just get the job done
1- use focusNode with timer
after you link foucsNode to the textfiled the button function could be something like this
onPressed: () {
Timer.periodic(Duration(microseconds: 1), (_) {
focusNode.unfocus();
});
//Write your code here
},
2- use stack
Stack(
alignment: Alignment.centerRight,
children: <Widget>[
TextField(
decoration: InputDecoration(
labelText: "Password",
border: OutlineInputBorder(),
),
),
IconButton(
icon: Icon(Icons.ac_unit),
onPressed: () {
//do any thing
},
),
],
),
3- as Afridi Kayal said you can use a row
Row(
children: <Widget>[
Expanded(
child: TextField(
focusNode: focusNode,
enabled: enabled,
autofocus: false,
textInputAction: TextInputAction.done,
decoration: InputDecoration(
labelText: "Password",
border: OutlineInputBorder(),
),
),
),
IconButton(
icon: Icon(Icons.visibility),
onPressed: () {
print('object');
},
),
],
),
if you end up going with number 2 or 3 and you want to make the button color change when you focus on the textfiled, you can do it by using focusNode as well.
I am using TextFormField in my Flutter app, like in this snippet:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(hintText: "TextField A"),
textInputAction: TextInputAction.next,
onSubmitted: (_) => FocusScope.of(context).nextFocus(), // move focus to next
),
TextField(
decoration: InputDecoration(hintText: "TextField B"),
textInputAction: TextInputAction.next,
onSubmitted: (_) => FocusScope.of(context).nextFocus(), // move focus to next
),
TextField(
decoration: InputDecoration(hintText: "TextField C"),
textInputAction: TextInputAction.done,
onSubmitted: (_) => FocusScope.of(context).unfocus(), // submit and hide keyboard
),
],
),
);
}
My problem is that whenever the next field is behind the keyboard, the keyboard just disappears instead of moving to the next focus...
This is a video of the problem:
https://www.youtube.com/watch?v=h-Cv2UpnHrY&feature=youtu.be
As you can see, my wanted behaviour is the focus to move from the email field to the address field, but instead the keyboard disappears and nothing happens.
How can I solve it?
I think you have to create a new object first of all that is..I am using another example just to demonstrate:
final FocusNode _emailFocusNode = FocusNode();
final FocusNode _passwordFocusNode = FocusNode();
TextField(
decoration: InputDecoration(
labelText: 'Email',
hintText: 'test#test.com',
errorText: emailErrorText),
textInputAction: TextInputAction.next,
keyboardType: TextInputType.emailAddress,
controller: _emailController,
focusNode: _emailFocusNode,
onEditingComplete: _newFocusNode
TextField(
decoration: InputDecoration(
labelText: 'Password',
errorText: passwordErrorText,
),
obscureText: true,
textInputAction: TextInputAction.done,
controller: _passwordController,
focusNode: _passwordFocusNode,
}
void _newFocusNode() {
final newFocus=_emailFocusNode?_passwordFocusNode:_emailFocusNode;
FocusScope.of(context).requestFocus(newFocus);
}
I have problem with flutter textformfield. Like I said in title my app show cursor in two textformfield. It appear when I tap previous textfield. I'm using real phone for test, not tried in emulator. Thanks for any help.
Here image from my app:
enter image description here
Form(
key: _formKey,
child: Column(
children: <Widget>[
SizedBox(
height: 20.0,
),
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
focusNode: _emailFocus,
onFieldSubmitted: (term) {
_passwordFocus.nextFocus();
_fieldFocusChange(
context, _emailFocus, _passwordFocus);
},
textInputAction: TextInputAction.next,
validator: (value) =>
value.isEmpty ? 'Enter an email' : null,
onChanged: (value) {
setState(() => email = value);
},
),
SizedBox(
height: 20.0,
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
validator: (value) => value.length < 6
? 'Enter an password 6+ chars long'
: null,
obscureText: true,
focusNode: _passwordFocus,
onFieldSubmitted: (term) {
_passwordFocus.unfocus();
_submitForm();
},
textInputAction: TextInputAction.done,
onChanged: (value) {
setState(() => password = value);
},
),
SizedBox(
height: 20.0,
),
RaisedButton(
color: Theme.of(context).primaryColor,
child: Text('Sign in'),
onPressed: () {
_submitForm();
},
),
SizedBox(height: 12.0),
Text(error,
style:
TextStyle(color: Colors.red, fontSize: 14.0)),
],
)),
I found solution from this question:
Multiple cursor in form's TextFormField flutter
It is same as mine. We did same mistake. When I declare FocusNode global it solve problem.
I have TextField purchaseCommentField() within the structure as below:
#override
Widget build(BuildContext context)
{
return GestureDetector(
onTap: CommonUtils.endEditing(context),
child: Container(
width: _width,
color: Colors.white,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
....
...
Visibility(
visible: _additionalInfo != null,
child: purchaseCommentField()
),
rowSpacer(16.0),
actionButton(context)
],
)
)
),
);
}
Widget purchaseCommentField()
{
return TextField(
controller: _purchaseCommentController,
minLines: 1,
maxLines: null,
keyboardType: TextInputType.multiline,
style: new TextStyle(fontSize: 14.0),
decoration: new InputDecoration(
labelText: 'Additional Info',
border: OutlineInputBorder(),
),
);
}
When I focus textfield, I got unwanted scrollbar at right inside the field:
This issue occured when I set fontSize:14.0. When I remove that or set fontSize to 16.0 then there is no scrollbar at right:
Is there a way to remove that scrollbar in textfield ?
try using TextFormField,
TextFormField(
controller: textController,
validator: (value) {
if (value.trim().isEmpty) {
return _reportTypeModel.language.msgEnterDesc;
}
return null;
},
style: new TextStyle(fontSize: 14.0),
maxLength: 500,
decoration: InputDecoration(
labelText: _reportTypeModel.language.description,
),
minLines: 4,
maxLines: 6,
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.next,
),
Output:
There's an open issue on github regarding this.
For now you can fix this by creating a custom ScrollBehavior and overriding buildScrollbar method:
class CustomScrollBehavior extends ScrollBehavior {
const CustomScrollBehavior();
#override
Widget buildScrollbar(context, child, details) {
return child;
}
}
And then wrap your TextField with ScrollConfiguration widget:
return ScrollConfiguration(
behavior: const CustomScrollConfiguration(),
child: TextField(
// Your text-field params
),
);
This works for TextFormField too.