如何使用表单管理speech_to_text

问题描述 投票:0回答:1

在我的 Flutter 应用程序中,我有一个将数据保存到 Firestore 的表单。 用户必须能够通过书写或口头输入数据。 为此,我已将 voice_to_text 插件附加到表单中。

问题是我还没有找到一种方法来同时管理说和写:例如,如果用户说话,然后修改文本,然后继续说话,我怎样才能在

TextFormField
中保持文本正确更新?

这是我的代码:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:speech_to_text/speech_to_text.dart';
import 'package:speech_to_text/speech_recognition_result.dart';

class Speech extends StatefulWidget {
  const Speech({super.key});

  @override
  State<Speech> createState() => _SpeechState();
}

class _SpeechState extends State<Speech> {
  bool _hasSpeech = false;
  String lastWords = '';
  String lastStatus = '';
  final SpeechToText speech = SpeechToText();

  bool textChanged = false;
  final TextEditingController _descriptionController = TextEditingController();

  @override
  void initState() {
    super.initState();
    _initSpeechState();
  }

  Future<void> _initSpeechState() async {
    try {
      bool hasSpeech = await speech.initialize();

      if (!mounted) return;

      setState(() {
        _hasSpeech = hasSpeech;
      });
    } catch (e) {
      setState(() {
        _hasSpeech = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(children: [
      // ApplicationState is the widget with the state of my app
      Consumer<ApplicationState>(builder: (context, appState, _) {
        return FutureBuilder<Baby>(
            future: appState.getBabyData(), // I recover the data from Firestore
            builder: (BuildContext context, AsyncSnapshot<Baby> snapshot) {
              if (!snapshot.hasData) {
                return const Center(
                  child: CircularProgressIndicator(),
                );
              } else {
                return MyForm(
                  baby: snapshot.requireData,
                  lastWords: lastWords,
                  descriptionController: _descriptionController,
                  stopListening: stopListening,
                  textChanged: textChanged,
                  setTextChanged: setTextChanged,
                );
              }
            });
      }),
      MicrophoneWidget(speech.isNotListening, startListening, stopListening),
    ]);
  }

  void setTextChanged(changed) {
    setState(() {
      textChanged = changed;
    });
  }

  void startListening() {
    lastWords = '';
    speech.listen(
      onResult: resultListener,
    );
    setState(() {
      textChanged = false;
    });
  }

  void stopListening() {
    speech.stop();
    setState(() {
      textChanged = false;
    });
  }

  void resultListener(SpeechRecognitionResult result) {
    setState(() {
      lastWords = result.recognizedWords;
      _descriptionController.text = lastWords;
    });
  }
}

class MicrophoneWidget extends StatelessWidget {
  const MicrophoneWidget(this.isNotListening, this.startListening, this.stopListening, {super.key});

  final bool isNotListening;
  final void Function() startListening;
  final void Function() stopListening;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      child: FloatingActionButton(
        onPressed: isNotListening ? startListening : stopListening,
        shape: const RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(80.0)),
        ),
        child: Icon(isNotListening ? Icons.mic_off : Icons.mic),
      ),
    );
  }
}

class MyForm extends StatefulWidget {
  const MyForm({
    super.key,
    required this.baby,
    required this.lastWords,
    required this.textChanged,
    required this.setTextChanged,
    required this.descriptionController,
    required this.stopListening,
  });

  final Baby baby;
  final String lastWords;
  final bool textChanged;
  final TextEditingController descriptionController;
  final void Function() stopListening;
  final void Function(bool) setTextChanged;

  @override
  State<MyForm> createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
  final _formKey = GlobalKey<FormState>(debugLabel: 'MyFormState');

  void _saveBabyProfile(appState) async {
    if (_formKey.currentState!.validate()) {
      widget.baby.description = widget.descriptionController.text;

      widget.stopListening;

      // I save the data in Firestore
      appState.setBabyData(widget.baby);
    }
  }

  @override
  Widget build(BuildContext context) {
    if (!widget.textChanged) {
      widget.descriptionController.text = widget.lastWords;
      if (widget.baby.description != null) {
        widget.descriptionController.text = '${widget.baby.description} ${widget.lastWords}';
      }
    }

    return Form(
      key: _formKey,
      child: Column(
        children: <Widget>[
          TextFormField(
            controller: widget.descriptionController,
            onChanged: (value) {
              widget.setTextChanged(true);
            },
          ),
          Consumer<ApplicationState>(
            builder: (context, appState, _) => ElevatedButton(
              onPressed: () => _saveBabyProfile(appState),
              child: const Text("Save"),
            ),
          ),
        ],
      ),
    );
  }
}

提前感谢您的帮助!

flutter forms dart input speech-to-text
1个回答
0
投票

您面临的问题是因为您在更改后没有保存新字符串。要解决这个问题,只需像这样调用 TextFormField 的

onChanged
上的 save 方法即可。

    onChanged: (value) {
              widget.setTextChanged(true);
                widget.baby.description = widget.descriptionController.text;
            },
© www.soinside.com 2019 - 2024. All rights reserved.