如何在Flutter中将speech_to_text识别文本添加到TextFieldTags组件的标签中?
问题描述
我在Flutter应用中使用TextFieldTags组件创建标签输入框,希望为其添加speech_to_text功能,让语音输入的文本直接显示在输入框中。目前我已经能在普通TextField中单独实现语音转文本功能,但无法将该功能与TextFieldTags组件集成。
原代码
TextFieldTags( textfieldTagsController: _controllerD, textSeparators: const [','], letterCase: LetterCase.normal, validator: (String tag) { diagnosis.add(tag); }, inputfieldBuilder: (context, tec, focus, error, onChanged, onSubmitted) { return ((context, sc, tags, onTagDelete) { return Padding( padding: const EdgeInsets.all(10.0), child: TextField( controller: tec, focusNode: focus, decoration: InputDecoration( isDense: true, border: const OutlineInputBorder( borderSide: BorderSide( color: Colors.blueGrey, width: 3.0, ), ), focusedBorder: const OutlineInputBorder( borderSide: BorderSide( color: Colors.blueGrey, width: 3.0, ), ), hintText: _controllerD.hasTags ? '' : "Enter patient's diagnosis...", errorText: error, prefixIconConstraints: BoxConstraints(maxWidth: _distanceToField * 0.74), prefixIcon: tags.isNotEmpty ? SingleChildScrollView( controller: sc, scrollDirection: Axis.horizontal, child: Row( children: tags.map((String tag) { return Container( decoration: const BoxDecoration( borderRadius: BorderRadius.all( Radius.circular(10.0), ), color: Colors.blueGrey, ), margin: const EdgeInsets.symmetric( horizontal: 5.0), padding: const EdgeInsets.symmetric( horizontal: 10.0, vertical: 5.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ InkWell( child: Text( '$tag', style: const TextStyle( color: Colors.white), ), onTap: () { print("$tag selected"); }, ), const SizedBox(width: 4.0), InkWell( child: const Icon( Icons.cancel, size: 14.0, color: Color.fromARGB( 255, 233, 233, 233), ), onTap: () { onTagDelete(tag); diagnosis.remove(tag); }, ) ], ), ); }).toList()), ) : null, ), onChanged: onChanged, onSubmitted: (tag){ FocusScope.of(context).requestFocus(focus); }, ), ); }); }, ),
解决方案
步骤1:初始化语音识别工具
首先在页面的State类中初始化SpeechToText实例,处理权限和监听逻辑:
import 'package:speech_to_text/speech_to_text.dart'; late SpeechToText _speechToText; bool _isListening = false; @override void initState() { super.initState(); _speechToText = SpeechToText(); // 可选:提前检查语音权限 _speechToText.initialize(); }
步骤2:修改TextFieldTags的输入框配置
在inputfieldBuilder返回的TextField中添加语音触发按钮,实现语音识别回调并将结果同步到组件控制器:
修改后的完整代码:
TextFieldTags( textfieldTagsController: _controllerD, textSeparators: const [','], letterCase: LetterCase.normal, validator: (String tag) { diagnosis.add(tag); }, inputfieldBuilder: (context, tec, focus, error, onChanged, onSubmitted) { return ((context, sc, tags, onTagDelete) { // 语音识别核心逻辑 void _toggleListening() async { if (!_isListening) { bool available = await _speechToText.initialize( onStatus: (status) => print('语音状态:$status'), onError: (error) => print('语音错误:$error'), ); if (available) { setState(() => _isListening = true); _speechToText.listen( onResult: (result) { setState(() { // 将语音结果赋值给输入框控制器 tec.text = result.recognizedWords; // 触发组件的输入变更回调,同步状态 onChanged(result.recognizedWords); }); }, ); } } else { setState(() => _isListening = false); _speechToText.stop(); } } return Padding( padding: const EdgeInsets.all(10.0), child: TextField( controller: tec, focusNode: focus, decoration: InputDecoration( isDense: true, border: const OutlineInputBorder( borderSide: BorderSide( color: Colors.blueGrey, width: 3.0, ), ), focusedBorder: const OutlineInputBorder( borderSide: BorderSide( color: Colors.blueGrey, width: 3.0, ), ), hintText: _controllerD.hasTags ? '' : "输入患者诊断...", errorText: error, prefixIconConstraints: BoxConstraints(maxWidth: _distanceToField * 0.74), prefixIcon: tags.isNotEmpty ? SingleChildScrollView( controller: sc, scrollDirection: Axis.horizontal, child: Row( children: tags.map((String tag) { return Container( decoration: const BoxDecoration( borderRadius: BorderRadius.all( Radius.circular(10.0), ), color: Colors.blueGrey, ), margin: const EdgeInsets.symmetric( horizontal: 5.0), padding: const EdgeInsets.symmetric( horizontal: 10.0, vertical: 5.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ InkWell( child: Text( '$tag', style: const TextStyle( color: Colors.white), ), onTap: () { print("$tag selected"); }, ), const SizedBox(width: 4.0), InkWell( child: const Icon( Icons.cancel, size: 14.0, color: Color.fromARGB( 255, 233, 233, 233), ), onTap: () { onTagDelete(tag); diagnosis.remove(tag); }, ) ], ), ); }).toList()), ) : null, // 添加语音控制按钮 suffixIcon: IconButton( icon: Icon( _isListening ? Icons.mic : Icons.mic_none, color: _isListening ? Colors.red : Colors.blueGrey, ), onPressed: _toggleListening, ), ), onChanged: onChanged, onSubmitted: (tag){ FocusScope.of(context).requestFocus(focus); }, ), ); }); }, ),
关键说明
- 利用
inputfieldBuilder提供的tec参数(TextField控制器),直接将语音识别结果赋值给它,确保输入框实时显示语音内容。 - 调用
onChanged方法同步输入状态,让TextFieldTags组件能正确处理后续的标签生成逻辑。 - 通过
_isListening状态变量切换语音按钮图标,直观反馈当前监听状态。
内容的提问来源于stack exchange,提问作者Rameen Akhter
相关产品推荐
相关产品推荐

