Multi-line TextField in Flutter - dart

It may sound easy but How can we do a multi-line editable textfield in flutter? TextField works only with a single line.
Edit: some precisions because seems like it's not clear.
While you can set multiline to virtually wrap the text content, it's still not multiline. It's a single line displayed into multiple lines.
If you want to do something like this then you can't. Because you don't have access to ENTER button. And no enter button means no multiline.

To use auto wrap, just set maxLines as null:
TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
)
If the maxLines property is null, there is no limit to the number of lines, and the wrap is enabled.

If you want your TextField be adapted to the user input then do this:
TextField(
keyboardType: TextInputType.multiline,
minLines: 1,//Normal textInputField will be displayed
maxLines: 5,// when user presses enter it will adapt to it
);
here you can set the max lines to whatever you want and you are good to go.
In my opinion setting the maxlines to null is not a good choice that's why we should set it to some value.

Although other people already mentioned that the keyboard type "TextInputType.multiline" can be used, I wanted to add my implementation of a TextField that automatically adapts its height when a new line is entered, as it is often desired to immitate the input behaviour of WhatsApp and similar apps.
I'm analyzing the number of '\n' chatacters in the input for this purpose each time the text is changed. This seems to be an overkill, but unfortunately I didn't find a better possibility to achieve this beahivour in Flutter so far and I didn't notice any performance problems even on older smartphones.
class _MyScreenState extends State<MyScreen> {
double _inputHeight = 50;
final TextEditingController _textEditingController = TextEditingController();
#override
void initState() {
super.initState();
_textEditingController.addListener(_checkInputHeight);
}
#override
void dispose() {
_textEditingController.dispose();
super.dispose();
}
void _checkInputHeight() async {
int count = _textEditingController.text.split('\n').length;
if (count == 0 && _inputHeight == 50.0) {
return;
}
if (count <= 5) { // use a maximum height of 6 rows
// height values can be adapted based on the font size
var newHeight = count == 0 ? 50.0 : 28.0 + (count * 18.0);
setState(() {
_inputHeight = newHeight;
});
}
}
// ... build method here
TextField(
controller: _textEditingController,
textInputAction: TextInputAction.newline,
keyboardType: TextInputType.multiline,
maxLines: null,
)

TextFormField(
minLines: 2,
maxLines: 5,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
hintText: 'description',
hintStyle: TextStyle(
color: Colors.grey
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
),
),

While this question is rather old, there is no extensive answer that explains how to dynamically resize the TextField with little developer effort. This is especially of major importance when the TextField is either placed in a flexbox such as ListView, SingleChildScrollView, etc. (the flexbox will not be able to determine the intrinsic size of an expandable TextField).
As suggested by many other users, build your TextField like so:
TextField(
textInputAction: TextInputAction.newline,
keyboardType: TextInputType.multiline,
minLines: null,
maxLines: null, // If this is null, there is no limit to the number of lines, and the text container will start with enough vertical space for one line and automatically grow to accommodate additional lines as they are entered.
expands: true, // If set to true and wrapped in a parent widget like [Expanded] or [SizedBox], the input will expand to fill the parent.
)
How to cope with the missing intrinsic height of the TextField?
Wrap the TextField in a IntrinsicHeight class to provide the dynamically computed intrinsic height of the expandable TextField to its parent (when requested via e.g. flexbox).

1. Fixed height:
(A) Based on lines:
TextField(
minLines: 3, // Set this
maxLines: 6, // and this
keyboardType: TextInputType.multiline,
)
(B) Based on height:
SizedBox(
height: 200, // <-- TextField expands to this height.
child: TextField(
maxLines: null, // Set this
expands: true, // and this
keyboardType: TextInputType.multiline,
),
)
2. Flexible height:
Use a Column and wrap the TextField in Expanded:
Column(
children: [
Expanded(
child: TextField(
maxLines: null, // Set this
expands: true, // and this
keyboardType: TextInputType.multiline,
),
),
],
)
(Optional) Set decoration:
You can se this decoration to any of the above TextField:
decoration: InputDecoration(
hintText: 'Write a message',
filled: true,
)

You have to use this line in the TextField widget :
maxLines: null,
if didn't work , just note that you have to delete this :
textInputAction: TextInputAction.next
it's disable multi line property action in the keyboard ..

use this
TextFormField(
keyboardType: TextInputType.multiline,
maxLines: //Number_of_lines(int),)

This Code Worked for me, Also I'm able to use ENTER for web & mobile.
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: ConstrainedBox(
// fit: FlexFit.loose,
constraints: BoxConstraints(
maxHeight: height,//when it reach the max it will use scroll
maxWidth: width,
),
child: const TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
minLines: 1,
decoration: InputDecoration(
fillColor: Colors.blueAccent,
filled: true,
hintText: "Type ",
border: InputBorder.none,
),
),
),
)
]);
}

TextField has maxLines property.

Use Expanded widget for dynamic feels
Expanded(
child: TextField(
keyboardType: TextInputType.multiline,
minLines: 1,
maxLines: 3,
),
)

if above once not worked for you then try add minLines also
TextField(
keyboardType: TextInputType.multiline,
minLines: 3,
maxLines: null);

For autowrap just use null for maxLines
TextFormField(
keyboardType: TextInputType.multiline,
maxLines: null,
)
or
TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
)

Official doc states:
The maxLines property can be set to null to remove the restriction on the number of lines. By default, it is one, meaning this is a single-line text field.
NOTE: maxLines must not be zero.

Specify TextInputAction.newline to make a TextField respond to the enter key and accept multi-line input:
textInputAction: TextInputAction.newline,

use this
Expanded(
child: TextField(
controller: textMessageController,
keyboardType: TextInputType.multiline,
textCapitalization: TextCapitalization.sentences,
minLines: 1,
maxLines: 3,
onChanged: ((value) {
setState(() {
_messageEntrer = value;
});
}),
decoration: InputDecoration(
hintText: "Type your message here",
hintMaxLines: 1,
contentPadding:
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 10),
hintStyle: TextStyle(
fontSize: 16,
),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: const BorderSide(
color: Colors.white,
width: 0.2,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: const BorderSide(
color: Colors.black26,
width: 0.2,
),
),
),
),
),

Related

Use keyboard arrows to move to next textformfield

I have created a contact form with a few textformfields. When I'm using the keyboard I want to also use the the arrows at the top of the keyboard to move to next textformfield. I have already implemented TextInputAction.next so that when clicking on "return" you go to next textformfield, but I also want to include the arrows to do the same to go up/down.
The image below shows the arrows I want to include action on.
This is my current textformfield code:
Widget _createTextField(controller, keyboardType, int maxLength, int maxLines, String hintText, double screenWidth) {
return Expanded(
child: TextFormField(
scrollPadding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
textCapitalization: TextCapitalization.sentences,
textInputAction: TextInputAction.next,
style: TextStyle(fontSize: (screenWidth > maxMobileScreenWidth) ? 16 : 12),
controller: controller,
keyboardType: keyboardType,
maxLength: maxLength,
maxLines: maxLines,
validator: (value) {
if (value!.isEmpty) {
return '* Required field';
}
return null;
},
decoration: InputDecoration(
counterText: "",
filled: true,
hintText: hintText,
hintStyle: const TextStyle(color: Colors.black45),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10.0)),
fillColor: const Color(0xff9ccb40),
),
),
);
}
You must use the Form() widget, on top of all your TextFromField.
you can use Form(child:Column(children:[])
suggest you to read this article

How can I hide letter counter from bottom of TextField in Flutter

I'm facing a small problem. As you can see, i have set maxLength 1 of TextField in Flutter, But i'm unable to hide bottom label of text counter.
To hide counter value from TextField or TextFormField widget while using maxLength attribute, try following:
TextField(
decoration: InputDecoration(
hintText: "Email",
counterText: "",
),
maxLength: 40,
),
In this, I have set counterText attribute inside InputDecoration property with empty value. Hope it will help.
This is the proper approach, it will prevent extra space below the Text Field, and also avoid extra code to set a null widget.
You can use input formatters in TextField
The following is:
inputFormatters:[
LengthLimitingTextInputFormatter(1),
]
Thank You!
you can use InputDecoratoin to hide letter counter.
TextFormField(
decoration: InputDecoration(
labelText: "username",
counterStyle: TextStyle(height: double.minPositive,),
counterText: ""
)
You can hide the counter by adding counterText: '', inside the textfield decoration. It will simply display an empty String.
Simply set counter to Offstage() will do the trick.
TextField(
maxLines: 1,
decoration: InputDecoration(
counter: Offstage(),
),
),
You can do:
TextField(
maxLength: 10,
buildCounter: (BuildContext context, { int currentLength, int maxLength, bool isFocused }) => null,
)
Most of the answers seem to work. Another way would be to assign the counter with a shrink SizeBox.
TextField(decoration: InputDecoration(
hintText: "Email",
counter: SizedBox.shrink()
),
maxLength: 40,
),
Add counterText: "", to InputDecoration
TextField(
decoration: InputDecoration(
counterText: "",
),
maxLength: 10,
),
Whenever you don't need something in flutter just put an empty container!
TextField(
decoration: InputDecoration(
hintText: "Email",
counter: Container(),
),
maxLength: 20,
),
Simply set buildCounter to null.
It is a callback that generates a custom [InputDecorator.counter] widget
TextField(
maxLength: (some length),
buildCounter: (BuildContext context, {int currentLength, int maxLength, bool isFocused}) => null,
);
This alone solved my problem!
TextField(
decoration: InputDecoration(
labelText: "Table Number",
counterText: ""
)
For null-safety use this:
TextField(
maxLength: 10,
buildCounter: (BuildContext context, {int? currentLength, int? maxLength, bool? isFocused}) => null,
)
You can use input formatters in TextField setting a limit to input and this is the best approach if you just want to hide the counter making a input limit.
import 'package:flutter/services.dart';
inputFormatters:[
LengthLimitingTextInputFormatter(1),
]
Or you can customize the decoration making a counter = Container():
decoration: InputDecoration(
hintText: "Email",
counter: Container(),
),
You if prefer to customize the buildCounter, here is how to do it properly (you can also customise the font, color etc). When you text field loses the focus the counter limits will disappears. Or you can just set
TextField(
controller: _clienteTextEditingController,
maxLength: 50,
buildCounter: (BuildContext context,
{int currentLength, int maxLength, bool isFocused}) {
return isFocused
? Text(
'The Input Limits are: $currentLength/$maxLength ',
style: new TextStyle(
fontSize: 10.0,
),
semanticsLabel: 'Input constraints',
)
: null;
},
),
you can use InputDecoratoin to hide the letter counter.
TextField(
keyboardType: TextInputType.number,
maxLength: 10,
decoration: InputDecoration(
**counterText:""**)
)
Another solution is to hide the counter widget by using SizedBox:
TextFormField(
...
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
counter: new SizedBox(
height: 0.0,
)),
...
)
You can follow the below codes.
TextField(
controller: myController,
maxLength: 3,
buildCounter: (BuildContext context, {int currentLength, int maxLength, bool isFocused}) =>null
)
Container(
height: 48,
alignment: Alignment.centerLeft,
padding: EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
border: Border.all(
color: CustomColors.kToDark,
),
color: CustomColors.White,
borderRadius: BorderRadius.all(Radius.circular(8))),
child: TextFormField(
textAlign: TextAlign.left,
cursorColor: CustomColors.kToDark,
maxLength: 30,
controller: _titleController,
keyboardType: TextInputType.text,
decoration: InputDecoration(
counterText: "",
border: InputBorder.none,
isDense: true,
contentPadding: EdgeInsets.all(0))),
),
Use counterText: "" inside InputDecoration()
In case you are still looking for the answer in 2020 here goes:
decoration: InputDecoration(
counter: Spacer(),
labelText: "National ID #",
border: InputBorder.none,
hintText: 'e.g 01-1234567A12',
hintStyle: TextStyle(color: Colors.grey)),
In the TextField, use a Spacer() as counter... hope this helps, i dont know if it breaks anything else but mine works fine.
Not pretty but works by removing the counter:
TextFormField(
buildCounter: (
BuildContext context, {
required int currentLength,
int? maxLength,
required bool isFocused,
}) => null,
Use a SizedBox.shrink() for the counter widget in InputDecoration:
Use a SizedBox with zero height and width:
TextField(
maxLength: 400,
decoration: InputDecoration(
counter: SizedBox(
width: 0,
height: 0,
),),)
As mentioned by #user10481267 in the best answer would be use buildCounter property. This gives extreme flexibility and you can even decide dynamically to show the counter or not.
I was building a dynamic form with the required properties in JSON. My implementation is as follows:
TextFormField(
buildCounter: (BuildContext context,
{
int currentLength,
int maxLength,
bool isFocused}) {
if (isFocused)
return formFields[index]["max"] == null
? null
: Text(
'$currentLength / $maxLength',
semanticsLabel: 'character count',
);
else
return null;
},
maxLength: formFields[index]["max"] ?? 100,
decoration: new InputDecoration(
labelText: formFields[index]["hint"] ?? "",
fillColor: Colors.green,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15.0),
borderSide: new BorderSide(),
),
)
)

How to make flutter TextField height match parent of container?

I want to make my TextField height the same as my container height. Please check my code below and let me know how can I make TextField match_parent of my container. I've checked this question The equivalent of wrap_content and match_parent in flutter? but I didn't find any solution. I need to make TextField to take full height and width of my container.
new Container(
height: 200.0,
decoration: new BoxDecoration(
border: new Border.all(color: Colors.black)
),
child: new SizedBox.expand(
child: new TextField(
maxLines: 2,
style: new TextStyle(
fontSize: 16.0,
// height: 2.0,
color: Colors.black
),
decoration: const InputDecoration(
hintText: "There is no data",
contentPadding: const EdgeInsets.symmetric(vertical: 40.0),
)
),
),
)
Please check the screenshot below. As said, I need my TextField to take full height of Container
Here is my solution:
Container(
height: 200,
color: Color(0xffeeeeee),
padding: EdgeInsets.all(10.0),
child: new ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 200.0,
),
child: new Scrollbar(
child: new SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse: true,
child: SizedBox(
height: 190.0,
child: new TextField(
maxLines: 100,
decoration: new InputDecoration(
border: InputBorder.none,
hintText: 'Add your text here',
),
),
),
),
),
),
),
It works pretty good for me. And here is a screen shot.
Answering this in 2021. There is an expands property available now. This code works:
Column(
children: [
Expanded(
child: TextField(
maxLines: null,
minLines: null,
expands: true,
),
flex: 1),
],
)
Let's remove a few lines in code and understand how flutter works.
Why we are giving height 200 to Container. Can't the Container adjust the height based on its child (in this case SizedBox.expand)
If we remove height 200, then Container occupied the entire screen because of SizedBox.expand
Do we really need the SizedBox for our use case. Let's remove that also see what happens.
Now our Container wraps the TextField. But there is some space above and below.
Who decided that space? TextField's decoration's contentPadding. Let's remove that also. It looks like below where textField wrapped by Container. Hope this is what you want. If not, please comment, we can tweak a bit and get what you want. Cheers
Final version of code which displays the above image
new Container(
// height: 200.0,
decoration: new BoxDecoration(
border: new Border.all(color: Colors.black)
),
child: new TextField(
maxLines: 2,
style: new TextStyle(
fontSize: 16.0,
// height: 2.0,
color: Colors.black
),
decoration: const InputDecoration(
hintText: "There is no data",
// contentPadding: const EdgeInsets.symmetric(vertical: 40.0),
)
),
)
Currently the only way to achieve the TextField to fill the available vertical space is:
TextField(maxLines: 1000000) //maxlines: any large int
While it is tempting to use TextField(maxLines: null), it will just set the TextField to expand with its content, until it reaches its container limit.
I think there needs to be a bool stretchVertically parameter. TextField(stretchVertically: true) would mean that the TextField will try to fill as much vertical space as it can. stretchVertically and maxLines would have to be mutually exclusive.

Flutter textfield that auto expands when text is entered and then starts scrolling the text when a certain height is reached

I've tried many configurations of the Flutter TextField but can't figure out how to build this one.
I'm looking for a textfield that is a single line initially and it auto expands as the text is entered into it and then at some point begins scrolling itself.
This can be achieved partially by using the maxLines: null attribute. But then when a lot of text is entered the Text in the textfield itself overflows.
And if the maxLines is set to a value then the whole textfield itself gets expanded to those many lines to start off with rather than beginning with a single line.
Is there a way to limit the height of textfield at some point like done in many chat apps like WhatsApp and telegram.
Container(
child: new ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 300.0,
),
child: TextField(
maxLines: null,
),
),
),
),
)
In older Flutter versions it was
Container(
child: new ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 300.0,
),
child: new Scrollbar(
child: new SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse: true,
child: new TextField(
maxLines: null,
),
),
),
),
)
Now we actually have minLines parameter of TextField, no workaround needed anymore.
TextField(
minLines: 1,
maxLines: 5,
)
The accepted answer by Gunter is good enough if you don't have any style for the TextField. But if you have at least an underline / bottom border for the TextField, it will disappear when scroll up.
My recommendation is to calculating the lines with TextPainter, then apply the calculated number of lines to TextField. Here's the code, replace your current TextField with LayoutBuilder :
LayoutBuilder(
builder: (context, size){
TextSpan text = new TextSpan(
text: yourTextController.text,
style: yourTextStyle,
);
TextPainter tp = new TextPainter(
text: text,
textDirection: TextDirection.ltr,
textAlign: TextAlign.left,
);
tp.layout(maxWidth: size.maxWidth);
int lines = (tp.size.height / tp.preferredLineHeight).ceil();
int maxLines = 10;
return TextField(
controller: yourTextController,
maxLines: lines < maxLines ? null : maxLines,
style: yourTextStyle,
);
}
)
TextField(
minLines: 1,
maxLines: 5,
maxLengthEnforced: true,
),

How to align Hint Text into centre in Text Field?

i am trying to add alignment to the hint-text inside Text-field.but it is not working. How to bring it to centre??
How to write text in curved shape???
Container(
child: new TextFormField(
controller: _pass,
textAlign: TextAlign.center,
decoration: new InputDecoration.collapsed(
hintText: " PASSWORD", ), )),
use textAlign: TextAlign.center, inside TextFormField or textfield
here is the code
The Output Like This
My problem was the auto content padding:
TextField(
textAlign: TextAlign.center,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0),
hintText: "hola mundo",
),
),
Happy coding.
The textHint will have the same Alignment as the input text. So you can try the code below to achieve what you're looking for:
TextFormField(
keyboardType: TextInputType.number,
maxLength: 5,
textAlign: TextAlign.center,
autofocus: true,
initialValue: '',
decoration: InputDecoration(
hintText: 'some hint',
counterText: "",
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5.0)),
),
);
Note: specific case, but might help others who tried everything else from this thread.
I had a design from which I copied all the paddings and alignments, but I somehow couldn't center the hint text, it was always a few pixels closer to the top edge.
The only thing that worked was finding out that there was a specific text height set in the design. After I applied that, everything aligned perfectly.
InputDecoration(
hintStyle: TextStyle(
fontSize: _smallFontSize, // or whatever
height: 1.4, // <----- this was the key
),
// other properties...
);
you can add textAlign: TextAlign.center to your code
here is my code and its works:
new Padding(
padding: new EdgeInsets.all(30.0),
child:
new TextField(
textAlign: TextAlign.center,
decoration: new InputDecoration(
border: new OutlineInputBorder(
borderSide: new BorderSide(color: Colors.teal)),
hintText: 'REF: 2',
),
),
),
all of the answers work for the fixed-sized text fields but in my case, I m using a dynamically sized container that parents my text field
AnimatedContainer(
width: (!widget.scrollController.hasClients ||
widget.scrollController.positions.length > 1)
? MediaQuery.of(context).size.width.toDouble()
: max(
MediaQuery.of(context).size.width -
widget.scrollController.offset.roundToDouble(),
(MediaQuery.of(context).size.width - 80.w).toDouble()),
duration: const Duration(milliseconds: 150),
constraints: BoxConstraints(maxHeight: 40.h),
margin: EdgeInsets.zero,
child: TextField(
controller: controller,
expands: true,
minLines: null,
maxLines: null,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
filled: true,
fillColor: MyAppColors.primaryColor1,
border: UnderlineInputBorder(
borderRadius:
BorderRadius.circular(15.w)),
prefixIcon: Icon(
Icons.search,
size: 20.w,
color: Theme.of(context).accentColor,
),
hintText: 'Songs, albums or artists',
contentPadding: EdgeInsets.zero,
hintStyle:
Theme.of(context).textTheme.subtitle2!.copyWith(
color: Colors.white.withOpacity(0.8),
fontSize: 18.sp,
)),
),
);
the solution that worked for me is that I set expand parameter to true and set these parameters:
minLines: null,
maxLines: null,
expands: true,
textAlignVertical: TextAlignVertical.center
the min and max line must be set to null in order to expand.
that is the only solution I found cuz in another way my hint text gain extra padding even I set the content padding to zero my hint text is not centered in other screen sizes.
You can use following attribute of TextFormField:
textAlign: TextAlign.center
This used to work earlier but now it doesn't. There's a recently opened issue in flutter repo which you can follow
Edit
Now works as expected.
textAlign: TextAlign.center will move your focus too, i fix it with some empty spaces in hint text
hintText: ' this is centred text)',

Resources