You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中将speech_to_text识别文本添加到TextFieldTags组件的标签中?

Flutter 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 11:10:21