Flutter自定义文本编辑器问题:选中容器文本下划线编辑失效
问题
开发一款不依赖flutter_quill等第三方包的自定义文本编辑器,需求是选中对应容器后,仅为该容器内的TextFormField文本添加下划线效果,但当前代码执行后无任何变化,需要修改代码实现逐个编辑的功能。
问题代码
View 代码
import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'editing_state.dart'; class EditingView extends StatefulWidget { const EditingView({super.key}); @override State<EditingView> createState() => _EditingViewState(); } class _EditingViewState extends State<EditingView> { final stateView = EditingState(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _formKey2 = GlobalKey(); TextDecoration? textDecoration; int selectedIndex = 1; final postItController = TextEditingController(); final postItController2 = TextEditingController(); final Map<String, int> fontTextDecorationMap = { 'None': 0, 'Underline': 1, }; final Map<String, List> formulasTextDecoration= { '0': [TextDecoration.none], '1': [TextDecoration.underline], }; List<TextDecoration> fontListTextDecoration = [ TextDecoration.none, TextDecoration.none ]; @override Widget build(BuildContext context) { void changeTextDecoration(textDecoration) { int? font = fontTextDecorationMap[textDecoration]; var resultado = formulasTextDecoration[font.toString()]?[0]; for(int i = 0; i < fontList.length; i ++){ if (selectedIndex == 1) { fontListTextDecoration[i + 1] = resultado; } else { fontListTextDecoration[selectedIndex] = resultado; } } } return Scaffold( appBar: AppBar( title: const Text('Editing')), body: Column( children: [ Container( height: 50, color:const Color(0xFFEBEEF3), padding: const EdgeInsets.all(5), child: Row( children: [ Observer( return GestureDetector( onTap: (){ textDecoration = TextDecoration.underline; changeTextDecoration(textDecoration); }, child: Container( decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(4)), color: stateView.highlight ? Colors.transparent : const Color(0x5FA1BFF8), ), child: const Icon( Icons.format_underline, color: Color(0xFF1F3359), ), ), ); } ), ] ), ), GestureDetector( onTap: () { setState(() { selectedIndex = 0; }); }, child: Container( height: 300, width: 300, padding: const EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.red, boxShadow: const [ BoxShadow( color: Color(0x3CC2C2C2), offset: Offset(5, 5), blurRadius: 2, spreadRadius: 0.01, ), ], ), child: Form( key: _formKey, child: TextFormField( controller: postItController, style: TextStyle( decoration: fontListTextDecoration[0], ), ), ), ), ), GestureDetector( onTap: () { setState(() { selectedIndex = 0; }); }, child: Container( height: 300, width: 300, padding: const EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.blue, boxShadow: const [ BoxShadow( color: Color(0x3CC2C2C2), offset: Offset(5, 5), blurRadius: 2, spreadRadius: 0.01, ), ], ), child: Form( key: _formKey2, child: TextFormField( controller: postItController2, style: TextStyle( decoration: fontListTextDecoration[1], ), ), ), ), ) ], ), ); } }
State 代码
import 'package:mobx/mobx.dart'; part 'editing_state.g.dart'; class EditingState = _EditingState with _$EditingState; abstract class _EditingState with Store { @observable bool _highlight = true; @computed bool get highlight => _highlight ; @action void changeHighlight() { _highlight = !_highlight ; } @action void resetState() { _highlight = true; } }
editing_state.g.dart 代码
// GENERATED CODE - DO NOT MODIFY BY HAND part of 'editing_state.dart'; // ************************************************************************** // StoreGenerator // ************************************************************************** // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers mixin _$EditingState on _EditingState, Store { Computed<bool>? _$highlightComputed; @override bool get highlight=> (_$highlightComputed ??= Computed<bool>(() => super.highlight, name: '_EditingState.highlight')) .value; late final _$_highlightAtom = Atom(name: '_EditingState._highlight', context: context); @override bool get _highlight { _$_highlightAtom.reportRead(); return super._highlight; } @override set _highlight(bool value) { _$_highlightAtom.reportWrite(value, super._highlight, () { super._highlight = value; }); } late final _$_EditingStateActionController = ActionController(name: '_EditingState', context: context); @override void changeHighlight() { final _$actionInfo = _$_EditingStateActionController.startAction( name: '_EditingState.changeHighlight'); try { return super.changeHighlight(); } finally { _$_EditingStateActionController.endAction(_$actionInfo); } } @override void resetState() { final _$actionInfo = _$_EditingStateActionController.startAction( name: '_EditingState.resetState'); try { return super.resetState(); } finally { _$_EditingStateActionController.endAction(_$actionInfo); } } @override String toString() { return ''' highlight: ${highlight} '''; } }
修复方案
以下是核心修改点及完整修复代码:
- 修正容器选中索引:第二个
GestureDetector的selectedIndex设为1,确保选中第二个容器时对应正确的文本框索引。 - 修复下划线功能参数传递:
changeTextDecoration接收字符串参数(匹配fontTextDecorationMap的key),而非TextDecoration对象,避免映射匹配失败。 - 简化样式更新逻辑:移除不必要的循环,直接更新选中索引对应的样式,修改后调用
setState触发UI刷新。 - 修正Observer语法:
Observer通过builder回调返回Widget,符合Mobx组件规范。 - 修正GestureDetector结构:确保
child属性正确包裹容器,语法符合Flutter要求。
修改后的完整View代码
import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'editing_state.dart'; class EditingView extends StatefulWidget { const EditingView({super.key}); @override State<EditingView> createState() => _EditingViewState(); } class _EditingViewState extends State<EditingView> { final stateView = EditingState(); final GlobalKey _formKey = GlobalKey(); final GlobalKey _formKey2 = GlobalKey(); int selectedIndex = 0; // 默认选中第一个容器 final postItController = TextEditingController(); final postItController2 = TextEditingController(); final Map<String, int> fontTextDecorationMap = { 'None': 0, 'Underline': 1, }; final Map<String, TextDecoration> formulasTextDecoration = { '0': TextDecoration.none, '1': TextDecoration.underline, }; List<TextDecoration> fontListTextDecoration = [ TextDecoration.none, TextDecoration.none ]; void changeTextDecoration(String decorationType) { int? fontType = fontTextDecorationMap[decorationType]; if (fontType != null) { TextDecoration? newDecoration = formulasTextDecoration[fontType.toString()]; if (newDecoration != null) { setState(() { fontListTextDecoration[selectedIndex] = newDecoration; }); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: const AppBar(title: Text('Editing')), body: Column( children: [ Container( height: 50, color: const Color(0xFFEBEEF3), padding: const EdgeInsets.all(5), child: Row( children: [ Observer(builder: (context) { return GestureDetector( onTap: () { stateView.changeHighlight(); changeTextDecoration('Underline'); }, child: Container( decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(4)), color: stateView.highlight ? Colors.transparent : const Color(0x5FA1BFF8), ), child: Icon( Icons.format_underline, color: stateView.highlight ? const Color(0xFF1F3359) : const Color.fromARGB(255, 20, 33, 56), ), ), ); }), ], ), ), GestureDetector( onTap: () { setState(() { selectedIndex = 0; }); }, child: Container( height: 300, width: 300, padding: const EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.red, boxShadow: const [ BoxShadow( color: Color(0x3CC2C2C2), offset: Offset(5, 5), blurRadius: 2, spreadRadius: 0.01, ), ], ), child: Form( key: _formKey, child: TextFormField( controller: postItController, style: TextStyle( decoration: fontListTextDecoration[0], ), ), ), ), ), GestureDetector( onTap: () { setState(() { selectedIndex = 1; // 修正为1,对应第二个文本框 }); }, child: Container( height: 300, width: 300, padding: const EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.blue, boxShadow: const [ BoxShadow( color: Color(0x3CC2C2C2), offset: Offset(5, 5), blurRadius: 2, spreadRadius: 0.01, ), ], ), child: Form( key: _formKey2, child: TextFormField( controller: postItController2, style: TextStyle( decoration: fontListTextDecoration[1], ), ), ), ), ), ], ), ); } }
修复说明
- 索引匹配:第二个容器选中索引改为1,与
fontListTextDecoration的索引一一对应,确保样式更新目标正确。 - 参数修正:传递字符串'Underline'给
changeTextDecoration,正确匹配映射表中的key,获取对应的下划线样式。 - UI刷新触发:修改样式后调用
setState,强制Flutter重新渲染文本框,应用新的样式。 - 组件规范修正:修复Observer的builder结构,符合Mobx的正确使用方式;调整GestureDetector的子组件包裹逻辑,解决语法错误。
- 性能优化:将
changeTextDecoration移到build方法外,避免每次build重复创建函数。
内容的提问来源于stack exchange,提问作者user121212121
相关产品推荐
相关产品推荐

