'Flutter - How to implement multiline underlined TextField
I want to implement the following Ui which contains a multiline TextField with underline below every single line. any idea on how I can implement this?
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: TextField(
controller: problemItem.titleController,
decoration: const InputDecoration(
border: InputBorder.none),
keyboardType: TextInputType.multiline,
minLines: 3,
maxLines: 100,
)
),
),
Solution 1:[1]
You can use a Stack to stack the TextField onto lines. You need to set the expands attribute of the TextField to true in order to make it expand to the full three-line width right from the start.
I implemented a similar TextField to the one you are trying to create:
Stack(
children: [
for (int i = 0; i < 3; i++)
Container(
width: double.infinity,
margin: EdgeInsets.only(
top: 4 + (i + 1) * 28,
left: 15,
right: 15,
),
height: 1,
color: Colors.black,
),
const SizedBox(
height: 97,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: TextField(
decoration: InputDecoration(border: InputBorder.none),
cursorHeight: 22,
style: TextStyle(
fontSize: 20.0,
),
keyboardType: TextInputType.multiline,
expands: true,
maxLines: null,
),
),
),
],
),
Solution 2:[2]
If you want to allocate a Fixed Lines Textfield, you can try the below widget:
style is required because it uses the text height to calculate the line
numberOfLines is the line number of underlines that need to be generated.
class UnderlineTextField extends StatelessWidget {
const UnderlineTextField({
required this.style,
required this.numberOfLines,
this.controller,
this.decoration = const InputDecoration(isDense: true),
this.keyboardType,
this.maxLines = 1,
this.minLines,
Key? key,
}) : super(key: key);
final TextEditingController? controller;
final InputDecoration? decoration;
final TextInputType? keyboardType;
final int? maxLines;
final int? minLines;
final int lines;
final TextStyle style;
@override
Widget build(BuildContext context) {
final textHeight = style.height ?? 20;
return Stack(
children: [
TextField(
style: style,
controller: controller,
decoration: decoration,
keyboardType: keyboardType,
maxLines: maxLines,
minLines: minLines,
),
Positioned.fill(
child: Padding(
padding: const EdgeInsets.only(top: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: List.generate(
numberOfLines,
(index) => Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: textHeight),
const Divider(height: 1, thickness: 1),
],
),
),
),
),
),
],
);
}
}
If you want to let the underline auto-added with the text content, you may need to add the listener inside the text controller and try to use TextPainter to calculate the number of lines:
... (inside the UnderlineTextField)
double maxWidth = 0;
controller?.addListener(() {
final text = controller?.text ?? '';
final textPainter = TextPainter(
text: TextSpan(text: text, style: style),
maxLines: maxLines,
textDirection: TextDirection.ltr,
);
textPainter.layout(maxWidth: maxWidth);
final numberOfLines = textPainter.computeLineMetrics().length;
});
return LayoutBuilder(
builder: (_, constrinat) {
maxWidth = constrinat.maxWidth;
...
Solution 3:[3]
Stack(
children: [
for (int i = 0; i < 4; i++)
Container(
margin: EdgeInsets.only(
top: 4 + (i + 1) * 28,
left: 15,
right: 15,
),
height: 2,
color: Colors.black,
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: TextField(
decoration: InputDecoration(border: InputBorder.none),
style: TextStyle(
fontSize: 20.0,
),
keyboardType: TextInputType.multiline,
expands: true,
maxLines: null,
),
),
],
),
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | TheUltimateOptimist |
| Solution 2 | |
| Solution 3 | Jhanvi Pathar |


