Flutter文本转语音插件text_to_speech的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter文本转语音插件text_to_speech的使用

Text To Speech

一个Flutter插件,提供TTS (Text-To-Speech) 服务。这个插件旨在提供iOS、Android、Web和macOS TTS API的大部分功能。

Getting Started

要使用此插件,在您的pubspec.yaml文件中添加text_to_speech作为依赖项:

dependencies:  
  text_to_speech: ^0.2.3

Installation

Android

  • 最低SDK版本:21
  • 针对SDK 30(Android 11)的应用程序需要在Android清单文件中的queries元素中声明TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE(参见Android文档)。
<queries>  
  <intent>  
      <action android:name="android.intent.action.TTS_SERVICE" />  
  </intent>  
 </queries>

iOS & macOS

  • iOS最低版本:7.0
  • macOS最低版本:10.14

(参见Apple文档

Features

Feature Android iOS Web macOS
speak
stop
pause -
resume -
set volume
set rate
set pitch
set language
get language
get voice

Usages

首先,在代码中导入依赖项:

import 'package:text_to_speech/text_to_speech.dart';  

然后,创建TextToSpeech类的实例:

TextToSpeech tts = TextToSpeech();  

Speak

String text = "Hello, Good Morning!";  
tts.speak(text);  

Set Volume

音量范围:0-1,其中0是静音,1是最大音量(默认行为)。

double volume = 1.0;  
tts.setVolume(volume);  

Set Rate

速率范围:0-2。 1.0是正常且默认的语速。较低的值会减慢语速(0.5是正常语速的一半)。较高的值会加快语速(2.0是正常语速的两倍)。

double rate = 1.0;  
tts.setRate(rate);  

Set Pitch

音调范围:0-2。 1.0是正常音调,较低的值会降低合成声音的音调,较高的值会提高音调。

double pitch = 1.0;  
tts.setPitch(pitch);  

Set Language

接受特定语言的locale标签名,例如’en-US’。您可以使用getLanguage函数检索支持的语言列表。

String language = 'en-US';  
tts.setLanguage(language);  

Get Languages

提供以locale标签格式表示的支持语言代码列表,例如’en-US’。您可以获取特定语言代码的显示名称

String language = 'en-US';  
tts.setLanguage(language);  

Get Voice

我们可以获取所有可用的声音或获取特定语言的声音。此函数将返回特定的声音名称。

List<String> voices = await tts.getVoices();  
  
String language = 'en-US';  
List<String> voices = await tts.getVoiceByLang(language);  

Native API Reference

  • Android TTS API: 链接
  • iOS/macOS AVSpeechSynthesizer API: 链接
  • Web Speech API: 链接

Example

完整的示例代码如下:

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:text_to_speech/text_to_speech.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final String defaultLanguage = 'en-US';

  TextToSpeech tts = TextToSpeech();

  String text = '';
  double volume = 1; // Range: 0-1
  double rate = 1.0; // Range: 0-2
  double pitch = 1.0; // Range: 0-2

  String? language;
  String? languageCode;
  List<String> languages = <String>[];
  List<String> languageCodes = <String>[];
  String? voice;

  TextEditingController textEditingController = TextEditingController();

  @override
  void initState() {
    super.initState();
    textEditingController.text = text;
    WidgetsBinding.instance?.addPostFrameCallback((_) {
      initLanguages();
    });
  }

  Future<void> initLanguages() async {
    /// populate lang code (i.e. en-US)
    languageCodes = await tts.getLanguages();

    /// populate displayed language (i.e. English)
    final List<String>? displayLanguages = await tts.getDisplayLanguages();
    if (displayLanguages == null) {
      return;
    }

    languages.clear();
    for (final dynamic lang in displayLanguages) {
      languages.add(lang as String);
    }

    final String? defaultLangCode = await tts.getDefaultLanguage();
    if (defaultLangCode != null && languageCodes.contains(defaultLangCode)) {
      languageCode = defaultLangCode;
    } else {
      languageCode = defaultLanguage;
    }
    language = await tts.getDisplayLanguageByCode(languageCode!);

    /// get voice
    voice = await getVoiceByLang(languageCode!);

    if (mounted) {
      setState(() {});
    }
  }

  Future<String?> getVoiceByLang(String lang) async {
    final List<String>? voices = await tts.getVoiceByLang(languageCode!);
    if (voices != null && voices.isNotEmpty) {
      return voices.first;
    }
    return null;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Text-to-Speech Example'),
        ),
        body: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(20.0),
            child: Center(
              child: Column(
                children: <Widget>[
                  TextField(
                    controller: textEditingController,
                    maxLines: 5,
                    decoration: const InputDecoration(
                        border: OutlineInputBorder(),
                        hintText: 'Enter some text here...'),
                    onChanged: (String newText) {
                      setState(() {
                        text = newText;
                      });
                    },
                  ),
                  Row(
                    children: <Widget>[
                      const Text('Volume'),
                      Expanded(
                        child: Slider(
                          value: volume,
                          min: 0,
                          max: 1,
                          label: volume.round().toString(),
                          onChanged: (double value) {
                            initLanguages();
                            setState(() {
                              volume = value;
                            });
                          },
                        ),
                      ),
                      Text('(${volume.toStringAsFixed(2)})'),
                    ],
                  ),
                  Row(
                    children: <Widget>[
                      const Text('Rate'),
                      Expanded(
                        child: Slider(
                          value: rate,
                          min: 0,
                          max: 2,
                          label: rate.round().toString(),
                          onChanged: (double value) {
                            setState(() {
                              rate = value;
                            });
                          },
                        ),
                      ),
                      Text('(${rate.toStringAsFixed(2)})'),
                    ],
                  ),
                  Row(
                    children: <Widget>[
                      const Text('Pitch'),
                      Expanded(
                        child: Slider(
                          value: pitch,
                          min: 0,
                          max: 2,
                          label: pitch.round().toString(),
                          onChanged: (double value) {
                            setState(() {
                              pitch = value;
                            });
                          },
                        ),
                      ),
                      Text('(${pitch.toStringAsFixed(2)})'),
                    ],
                  ),
                  Row(
                    children: <Widget>[
                      const Text('Language'),
                      const SizedBox(
                        width: 20,
                      ),
                      DropdownButton<String>(
                        value: language,
                        icon: const Icon(Icons.arrow_downward),
                        iconSize: 24,
                        elevation: 16,
                        style: const TextStyle(color: Colors.deepPurple),
                        underline: Container(
                          height: 2,
                          color: Colors.deepPurpleAccent,
                        ),
                        onChanged: (String? newValue) async {
                          languageCode =
                              await tts.getLanguageCodeByName(newValue!);
                          voice = await getVoiceByLang(languageCode!);
                          setState(() {
                            language = newValue;
                          });
                        },
                        items: languages
                            .map<DropdownMenuItem<String>>((String value) {
                          return DropdownMenuItem<String>(
                            value: value,
                            child: Text(value),
                          );
                        }).toList(),
                      ),
                    ],
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  Row(
                    children: <Widget>[
                      const Text('Voice'),
                      const SizedBox(
                        width: 20,
                      ),
                      Text(voice ?? '-'),
                    ],
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  Row(
                    children: <Widget>[
                      Expanded(
                        child: Container(
                          padding: const EdgeInsets.only(right: 10),
                          child: ElevatedButton(
                            child: const Text('Stop'),
                            onPressed: () {
                              tts.stop();
                            },
                          ),
                        ),
                      ),
                      if (supportPause)
                        Expanded(
                          child: Container(
                            padding: const EdgeInsets.only(right: 10),
                            child: ElevatedButton(
                              child: const Text('Pause'),
                              onPressed: () {
                                tts.pause();
                              },
                            ),
                          ),
                        ),
                      if (supportResume)
                        Expanded(
                          child: Container(
                            padding: const EdgeInsets.only(right: 10),
                            child: ElevatedButton(
                              child: const Text('Resume'),
                              onPressed: () {
                                tts.resume();
                              },
                            ),
                          ),
                        ),
                      Expanded(
                          child: Container(
                        child: ElevatedButton(
                          child: const Text('Speak'),
                          onPressed: () {
                            speak();
                          },
                        ),
                      ))
                    ],
                  )
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  bool get supportPause => defaultTargetPlatform != TargetPlatform.android;

  bool get supportResume => defaultTargetPlatform != TargetPlatform.android;

  void speak() {
    tts.setVolume(volume);
    tts.setRate(rate);
    if (languageCode != null) {
      tts.setLanguage(languageCode!);
    }
    tts.setPitch(pitch);
    tts.speak(text);
  }
}

TODO

  • ❌ Utterance Status Listener
  • ❌ Linux Implementation
  • ❌ Windows Implementation

更多关于Flutter文本转语音插件text_to_speech的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter文本转语音插件text_to_speech的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter应用中使用text_to_speech插件来实现文本转语音功能的代码示例。这个插件允许你在Flutter应用中轻松集成文本转语音功能。

步骤 1: 添加依赖

首先,你需要在pubspec.yaml文件中添加text_to_speech依赖:

dependencies:
  flutter:
    sdk: flutter
  text_to_speech: ^5.3.0  # 请确保使用最新版本

然后运行flutter pub get来安装依赖。

步骤 2: 导入插件

在你的Dart文件中导入text_to_speech插件:

import 'package:text_to_speech/text_to_speech.dart';

步骤 3: 使用插件

以下是一个简单的示例,展示了如何在Flutter应用中使用text_to_speech插件:

import 'package:flutter/material.dart';
import 'package:text_to_speech/text_to_speech.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Text to Speech Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final TextToSpeech _tts = TextToSpeech();

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

  Future<void> _initTts() async {
    bool isAvailable = await _tts.isLanguageAvailable("en-US");
    if (isAvailable) {
      setState(() {});
    } else {
      // Language not supported
    }
  }

  Future<void> _speak(String text) async {
    try {
      await _tts.setLanguage("en-US");
      await _tts.speak(text);
    } catch (e) {
      print("Failed to speak: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Text to Speech Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Hello, press the button to listen to a message!',
              style: TextStyle(fontSize: 24),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                _speak("Hello, this is a text to speech demo.");
              },
              child: Text('Speak'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _tts.stop();
    _tts.dispose();
    super.dispose();
  }
}

解释

  1. 依赖添加:在pubspec.yaml文件中添加text_to_speech依赖。
  2. 导入插件:在需要使用文本转语音功能的Dart文件中导入text_to_speech插件。
  3. 初始化插件:在initState方法中调用_initTts方法来检查并初始化TTS插件。
  4. 文本转语音功能_speak方法接受一个字符串参数,并使用_tts.speak方法将其转换为语音。
  5. UI部分:一个简单的UI,包含一个按钮,点击按钮时调用_speak方法。
  6. 资源释放:在dispose方法中停止并释放TTS资源。

这个示例展示了如何在Flutter应用中使用text_to_speech插件来实现基本的文本转语音功能。你可以根据需要进一步扩展和优化这个示例。

回到顶部