在我的 Flutter 应用程序中,我有一个包含各种
TextFormFields
的表单,每个表单都有一个麦克风来转录所说的内容。
我用SpeechToTextProvider
实现了它。
当我按下麦克风时,它会写入正确的输入,但是所有麦克风都会激活(只有一个提供程序),并且
setState
会更新所有输入,而不仅仅是用户选择的输入。
如何确保一次只选择并重建一个麦克风?
感谢任何可以帮助我的人!
这是根中
speechProvider
的初始化:
final SpeechToText speech = SpeechToText();
late SpeechToTextProvider speechProvider;
@override
void initState() {
super.initState();
speechProvider = SpeechToTextProvider(speech);
initSpeechState();
}
Future<void> initSpeechState() async {
await speechProvider.initialize();
}
然后我在根小部件中添加
ChangeNotifierProvider
:
ChangeNotifierProvider<SpeechToTextProvider>.value(value: speechProvider),
这是表格:
class DayForm extends StatefulWidget {
const DayForm({required this.days, super.key});
final Map<int, Day> days;
@override
State<DayForm> createState() => _DayFormState();
}
class _DayFormState extends State<DayForm> {
Map<int, Day> get days => widget.days;
final _formKey = GlobalKey<FormState>(debugLabel: "DayForm");
late final Map<int, dynamic> _daysFields = {};
void _setLastTextChange(inputKey, lastText) {
setState(() {
_daysFields[inputKey]["lastTextChange"] = lastText;
});
}
@override
void initState() {
super.initState();
for (int dayNumber = 1; dayNumber <= 7; dayNumber++) {
_daysFields[dayNumber] = {
"controller": TextEditingController(),
"lastTextChange": "",
};
}
days.forEach((key, value) {
_daysFields[key]["controller"].text = value.description ?? "";
_setLastTextChange(key, _daysFields[key]["controller"].text);
});
}
@override
Widget build(BuildContext context) {
var formFields = <Widget>[];
_daysFields.forEach((key, value) {
formFields.add(Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
key: UniqueKey(), // here or in Padding is the same
children: [
Expanded(
child: TextFormField(
controller: value["controller"],
onChanged: (changed) {
_setLastTextChange(key, changed);
},
),
),
SpeechProvider(
key: ValueKey(key),
controller: value["controller"],
lastInputChange: value["lastTextChange"],
setLastInputChange: _setLastTextChange,
),
],
),
));
});
return Consumer<ApplicationState>(
builder: (context, appState, _) {
return Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: formFields,
),
),
);
},
);
}
}
这是调用的代码
SpeechToTextProvider
:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text_provider.dart';
class SpeechProvider extends StatefulWidget {
const SpeechProvider({
super.key,
required this.controller,
required this.lastInputChange,
required this.setLastInputChange,
});
final TextEditingController controller;
final String lastInputChange;
final void Function(dynamic, String) setLastInputChange;
@override
SpeechProviderState createState() => SpeechProviderState();
}
class SpeechProviderState extends State<SpeechProvider> {
String lastWords = '';
late SpeechToTextProvider speechProvider;
void startListening() {
if (speechProvider.isAvailable && speechProvider.isNotListening) {
lastWords = '';
speechProvider.listen();
speechProvider.stream.listen((event) {
final result = event.recognitionResult;
if (result != null) {
resultListener(result);
}
});
setState(() {});
}
}
void stopListening() {
if (!mounted) return;
if (speechProvider.isListening) {
speechProvider.stop();
setState(() {
widget.setLastInputChange((widget.key as ValueKey<dynamic>).value, widget.controller.text);
});
}
}
void resultListener(SpeechRecognitionResult result) {
if (!mounted) return;
setState(() {
if (result.finalResult) {
widget.setLastInputChange((widget.key as ValueKey<dynamic>).value, widget.controller.text);
} else {
lastWords = result.recognizedWords;
widget.controller.text = '${widget.lastInputChange} $lastWords';
}
});
}
@override
Widget build(BuildContext context) {
speechProvider = Provider.of<SpeechToTextProvider>(context);
return TapRegion(
onTapOutside: (tap) => speechProvider.isListening ? stopListening() : null,
child: SizedBox(
child: FloatingActionButton(
onPressed: speechProvider.isListening ? stopListening : startListening,
child: Icon(speechProvider.isListening ? Icons.mic : Icons.mic_off),
),
),
);
}
}
尝试独立管理每个麦克风的状态。