Flutter自定义AppTextField组件maxLines属性异常问题排查与解决
Hey, let's break down why your multi-line text field is acting up and fix it right away:
The core problem is that the Container wrapping your TextField doesn't have a proper width constraint. By default, Container shrinks to fit its child's size. When you set maxLines and use TextInputType.multiline, the TextField keeps narrowing itself as you type—ending up with only one character per line because there's no forced width to fill.
Also, a small best practice: when using TextInputType.multiline, it’s usually better to specify both minLines and maxLines to give the text field a stable initial height and avoid odd layout quirks.
You have two solid options to resolve this:
Option 1: Force the Container to Fill Available Width
Make the Container take up all horizontal space in its parent. This gives the TextField enough room to expand properly:
@override Widget build(BuildContext context) => Container( width: double.infinity, // This line forces the container to fill available width child: TextField( textDirection: isRTL(text!) ? TextDirection.rtl : TextDirection.ltr, textInputAction: widget.inputAction, keyboardType: widget.keyboardType, autofocus: widget.autoFocus, style: Theme.of(context).textTheme.bodyText1, maxLines: widget.maxLines, decoration: InputDecoration( labelText: widget.title, // Use SizedBox.shrink() instead of empty Container—it’s lighter and doesn’t take extra space suffixIcon: widget.isSuffixIcon ? Icon(Icons.check_circle, color: Theme.of(context).hintColor) : SizedBox.shrink(), ), onChanged: (value) { setState(() { text = value; }); } ));
Option 2: Add minLines Parameter for Better Layout Control
Update your AppTextField component to support minLines, which gives you more flexibility when using multi-line input:
First, update the StatefulWidget to include the new parameter:
class AppTextField extends StatefulWidget { final int maxLines; final int? minLines; // New parameter for initial line count final String? title; final TextInputType? keyboardType; final bool autoFocus; final TextInputAction inputAction; final bool isSuffixIcon; AppTextField({ this.title, this.maxLines = 1, this.minLines, this.keyboardType, this.autoFocus = false, this.inputAction = TextInputAction.next, this.isSuffixIcon = false, }); @override State<StatefulWidget> createState() => AppTextFieldSate(); }
Then use the minLines parameter in the TextField:
@override Widget build(BuildContext context) => Container( width: double.infinity, child: TextField( textDirection: isRTL(text!) ? TextDirection.rtl : TextDirection.ltr, textInputAction: widget.inputAction, keyboardType: widget.keyboardType, autofocus: widget.autoFocus, style: Theme.of(context).textTheme.bodyText1, maxLines: widget.maxLines, minLines: widget.minLines, // Apply the new parameter decoration: InputDecoration( labelText: widget.title, suffixIcon: widget.isSuffixIcon ? Icon(Icons.check_circle, color: Theme.of(context).hintColor) : SizedBox.shrink(), ), onChanged: (value) { setState(() { text = value; }); } ));
Now when you call the component, you can set both line parameters for a smoother experience:
AppTextField( maxLines: 5, minLines: 1, // Or set to 5 if you want it to start as a full 5-line box keyboardType: TextInputType.multiline, )
内容的提问来源于stack exchange,提问作者Ehsan Kalali

