Flutter中如何限制TextFormField达到maxLines行数上限后禁止输入
核心原因
TextFormField的maxLines参数仅控制输入框组件的最大展示高度,对应最多可同时展示的文本行数,超出部分会在输入框内滚动,默认不会拦截后续输入,属于组件的正常设计表现,不是参数失效。
实现方案
通过自定义TextInputFormatter实时计算输入内容的实际渲染行数,达到行数上限时直接拦截新输入即可,这种方案可以同时覆盖手动换行、文本自动折行两种场景,不会出现漏拦截的问题。
- 自定义行数限制输入格式化器:
class MaxLinesInputFormatter extends TextInputFormatter { final int maxLines; final TextStyle textStyle; final double availableWidth; MaxLinesInputFormatter({ required this.maxLines, required this.textStyle, required this.availableWidth, }); @override TextEditingValue formatEditUpdate( TextEditingValue oldValue, TextEditingValue newValue, ) { final textPainter = TextPainter( text: TextSpan(text: newValue.text, style: textStyle), textDirection: TextDirection.ltr, maxLines: maxLines, )..layout(maxWidth: availableWidth); return textPainter.didExceedMaxLines ? oldValue : newValue; } }
- 替换原有代码中
inputFormatters数组的占位内容,传入计算行数需要的参数即可,修改后的完整组件代码如下:
// 定义输入文本样式,和你实际使用的文本样式保持一致 const inputTextStyle = TextStyle(color: Colors.white, fontSize: 14); TextFormField( controller: _contextController, cursorColor: Colors.white, textAlign: TextAlign.center, focusNode: _contextFocus, keyboardType: TextInputType.multiline, minLines: 1, maxLines: 5, style: inputTextStyle, inputFormatters: [ MaxLinesInputFormatter( maxLines: 5, textStyle: inputTextStyle, // 输入框左右内边距各20,总扣减40,如果输入框外层有额外padding/margin要同步扣减 availableWidth: MediaQuery.of(context).size.width - 40, ) ], decoration: InputDecoration( fillColor: Color(0xBD000000), filled: true, enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, border: InputBorder.none, errorBorder: InputBorder.none, contentPadding: EdgeInsets.all(20), hintText: _contextHint, hintStyle: TextStyle(color: Colors.white)), )
避坑提示
- 不要使用统计换行符
\n数量的方案做限制,这种方案无法识别文本自动折行产生的新行,会出现视觉上已经超出5行但仍可输入的问题 - 如果输入框不是撑满全屏宽度,需要把
availableWidth替换为输入框实际占用宽度减去左右内边距的数值,否则行数计算会有偏差 - 如果设置了自定义行高、
strutStyle,需要把对应参数同步传入格式化器内的TextPainter,保证计算结果和实际渲染行数一致。
内容的提问来源于stack exchange,提问作者DW_Cod
相关产品推荐
相关产品推荐

