Flutter:如何让提供者只重建一个小部件

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

在我的 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),
        ),
      ),
    );
  }
}
flutter forms input speech-to-text
1个回答
0
投票

尝试独立管理每个麦克风的状态。

© www.soinside.com 2019 - 2024. All rights reserved.