Flutter 颤振-下划线或绘制文字文字到语音(TTS)
我有一个颤振程序,可以从文本翻译成语音,但我有一个问题,如何强调它所说的内容?也就是说,所说的每一个单词都有下划线或涂鸦,我希望有人能帮助我,非常感谢。我猜您在TTS期间会收到一个进度回调,其中包含开始值和结束值。只需将文本分为三部分(开始前一部分、开始和结束之间的一部分、结束后一部分),然后将它们分配到三个文本span中,并添加相应的注释。本讨论将有助于您: 以下是讨论中提供的要点代码:Flutter 颤振-下划线或绘制文字文字到语音(TTS),flutter,text-to-speech,underline,Flutter,Text To Speech,Underline,我有一个颤振程序,可以从文本翻译成语音,但我有一个问题,如何强调它所说的内容?也就是说,所说的每一个单词都有下划线或涂鸦,我希望有人能帮助我,非常感谢。我猜您在TTS期间会收到一个进度回调,其中包含开始值和结束值。只需将文本分为三部分(开始前一部分、开始和结束之间的一部分、结束后一部分),然后将它们分配到三个文本span中,并添加相应的注释。本讨论将有助于您: 以下是讨论中提供的要点代码: import 'dart:async'; import 'dart:io' show Platform;
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
enum TtsState { playing, stopped, paused, continued }
class _MyAppState extends State<MyApp> {
late FlutterTts flutterTts;
dynamic languages;
String? language;
double volume = 0.5;
double pitch = 1.0;
double rate = 0.5;
bool isCurrentLanguageInstalled = false;
int start = 0;
int end = 0;
String? _newVoiceText;
TtsState ttsState = TtsState.stopped;
get isPlaying => ttsState == TtsState.playing;
get isStopped => ttsState == TtsState.stopped;
get isPaused => ttsState == TtsState.paused;
get isContinued => ttsState == TtsState.continued;
bool get isIOS => !kIsWeb && Platform.isIOS;
bool get isAndroid => !kIsWeb && Platform.isAndroid;
bool get isWeb => kIsWeb;
@override
initState() {
super.initState();
initTts();
}
initTts() {
flutterTts = FlutterTts();
_getLanguages();
if (isAndroid) {
_getEngines();
}
flutterTts.setStartHandler(() {
setState(() {
print("Playing");
ttsState = TtsState.playing;
});
});
flutterTts.setCompletionHandler(() {
setState(() {
print("Complete");
ttsState = TtsState.stopped;
});
});
flutterTts.setCancelHandler(() {
setState(() {
print("Cancel");
ttsState = TtsState.stopped;
});
});
if (isWeb || isIOS) {
flutterTts.setPauseHandler(() {
setState(() {
print("Paused");
ttsState = TtsState.paused;
});
});
flutterTts.setContinueHandler(() {
setState(() {
print("Continued");
ttsState = TtsState.continued;
});
});
}
flutterTts.setErrorHandler((msg) {
setState(() {
print("error: $msg");
ttsState = TtsState.stopped;
});
});
flutterTts.setProgressHandler(
(String text, int startOffset, int endOffset, String word) {
setState(() {
start = startOffset;
end = endOffset;
});
});
}
Future _getLanguages() async {
languages = await flutterTts.getLanguages;
if (languages != null) setState(() => languages);
}
Future _getEngines() async {
var engines = await flutterTts.getEngines;
if (engines != null) {
for (dynamic engine in engines) {
print(engine);
}
}
}
Future _speak() async {
await flutterTts.setVolume(volume);
await flutterTts.setSpeechRate(rate);
await flutterTts.setPitch(pitch);
if (_newVoiceText != null) {
await flutterTts.awaitSpeakCompletion(true);
await flutterTts.speak(_newVoiceText!);
}
}
Future _stop() async {
var result = await flutterTts.stop();
if (result == 1) setState(() => ttsState = TtsState.stopped);
}
Future _pause() async {
var result = await flutterTts.pause();
if (result == 1) setState(() => ttsState = TtsState.paused);
}
@override
void dispose() {
super.dispose();
flutterTts.stop();
}
List<DropdownMenuItem<String>> getLanguageDropDownMenuItems() {
var items = <DropdownMenuItem<String>>[];
for (dynamic type in languages) {
items.add(DropdownMenuItem(value: type as String, child: Text(type)));
}
return items;
}
void changedLanguageDropDownItem(String? selectedType) {
setState(() {
language = selectedType;
flutterTts.setLanguage(language!);
if (isAndroid) {
flutterTts
.isLanguageInstalled(language!)
.then((value) => isCurrentLanguageInstalled = (value as bool));
}
});
}
void _onChange(String text) {
setState(() {
_newVoiceText = text;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter TTS'),
),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(children: [
_inputSection(),
ttsState == TtsState.playing
? _textFromInput(start, end)
: Text(""),
_btnSection(),
languages != null ? _languageDropDownSection() : Text(""),
_buildSliders()
]))));
}
Widget _inputSection() => Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0),
child: TextField(
onChanged: (String value) {
_onChange(value);
start = 0;
end = value.length;
},
));
Widget _textFromInput(int start, int end) => Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(children: <TextSpan>[
TextSpan(
text: _newVoiceText != null && start != 0
? _newVoiceText!.substring(0, start)
: "",
style: TextStyle(color: Colors.black)),
TextSpan(
text: _newVoiceText != null
? _newVoiceText!.substring(start, end)
: "",
style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold)),
TextSpan(
text: _newVoiceText != null ? _newVoiceText!.substring(end) : "",
style: TextStyle(color: Colors.black)),
]),
));
Widget _btnSection() {
if (isAndroid) {
return Container(
padding: EdgeInsets.only(top: 50.0),
child:
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
_buildButtonColumn(Colors.green, Colors.greenAccent,
Icons.play_arrow, 'PLAY', _speak),
_buildButtonColumn(
Colors.red, Colors.redAccent, Icons.stop, 'STOP', _stop),
]));
} else {
return Container(
padding: EdgeInsets.only(top: 50.0),
child:
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
_buildButtonColumn(Colors.green, Colors.greenAccent,
Icons.play_arrow, 'PLAY', _speak),
_buildButtonColumn(
Colors.red, Colors.redAccent, Icons.stop, 'STOP', _stop),
_buildButtonColumn(
Colors.blue, Colors.blueAccent, Icons.pause, 'PAUSE', _pause),
]));
}
}
Widget _languageDropDownSection() => Container(
padding: EdgeInsets.only(top: 50.0),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [
DropdownButton(
value: language,
items: getLanguageDropDownMenuItems(),
onChanged: changedLanguageDropDownItem,
),
Visibility(
visible: isAndroid,
child: Text("Is installed: $isCurrentLanguageInstalled"),
),
]));
Column _buildButtonColumn(Color color, Color splashColor, IconData icon,
String label, Function func) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(icon),
color: color,
splashColor: splashColor,
onPressed: () => func()),
Container(
margin: const EdgeInsets.only(top: 8.0),
child: Text(label,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: color)))
]);
}
Widget _buildSliders() {
return Column(
children: [_volume(), _pitch(), _rate()],
);
}
Widget _volume() {
return Slider(
value: volume,
onChanged: (newVolume) {
setState(() => volume = newVolume);
},
min: 0.0,
max: 1.0,
divisions: 10,
label: "Volume: $volume");
}
Widget _pitch() {
return Slider(
value: pitch,
onChanged: (newPitch) {
setState(() => pitch = newPitch);
},
min: 0.5,
max: 2.0,
divisions: 15,
label: "Pitch: $pitch",
activeColor: Colors.red,
);
}
Widget _rate() {
return Slider(
value: rate,
onChanged: (newRate) {
setState(() => rate = newRate);
},
min: 0.0,
max: 1.0,
divisions: 10,
label: "Rate: $rate",
activeColor: Colors.green,
);
}
}
导入'dart:async';
导入“dart:io”展示平台;
导入“包:flatter/foundation.dart”显示kIsWeb;
进口“包装:颤振/材料.省道”;
进口“包装:颤振_tts/颤振_tts.dart”;
void main()=>runApp(MyApp());
类MyApp扩展了StatefulWidget{
@凌驾
_MyAppState createState()=>\u MyAppState();
}
枚举TtsState{播放、停止、暂停、继续}
类MyAppState扩展了状态{
晚发颤音;
动态语言;
字符串语言;
双体积=0.5;
双节距=1.0;
倍率=0.5;
bool isCurrentLanguageInstalled=false;
int start=0;
int end=0;
字符串?\u新语音文本;
TtsState TtsState=TtsState.stopped;
获取isplay=>ttsState==ttsState.playing;
get-isStopped=>ttsState==ttsState.stopped;
get isPaused=>ttsState==ttsState.paused;
get isContinued=>ttsState==ttsState.continued;
bool get isIOS=>!kIsWeb&&Platform.isIOS;
bool get isAndroid=>!kIsWeb&&Platform.isAndroid;
bool-get-isWeb=>kIsWeb;
@凌驾
initState(){
super.initState();
initTts();
}
initTts(){
颤振tts=颤振tts();
_getLanguages();
if(isAndroid){
_getEngines();
}
颤振设置开始处理程序(){
设置状态(){
打印(“播放”);
ttsState=ttsState.playing;
});
});
flattertts.setCompletionHandler((){
设置状态(){
打印(“完整”);
ttsState=ttsState.stopped;
});
});
flattertts.setCancelHandler((){
设置状态(){
打印(“取消”);
ttsState=ttsState.stopped;
});
});
如果(isWeb | | isIOS){
颤振设置Pausehandler(){
设置状态(){
打印(“暂停”);
ttsState=ttsState.paused;
});
});
flatterts.setContinueHandler(){
设置状态(){
印刷品(续);
ttsState=ttsState.continued;
});
});
}
flattertts.setErrorHandler((msg){
设置状态(){
打印(“错误:$msg”);
ttsState=ttsState.stopped;
});
});
fluttts.setProgressHandler(
(字符串文本、int-startOffset、int-endOffset、字符串字){
设置状态(){
start=STARTOFSET;
结束=内偏移;
});
});
}
Future\u getLanguages()异步{
语言=等待颤振tts.getLanguages;
如果(语言!=null)设置状态(()=>语言);
}
Future\u getEngines()异步{
var发动机=等待颤振TTS.getEngines;
如果(引擎!=null){
用于(发动机中的动态发动机){
打印(引擎);
}
}
}
Future\u speak()异步{
等待颤振。设置音量(音量);
等待颤振设置速度(速率);
等待颤振。设置螺距(螺距);
如果(_newVoiceText!=null){
等待颤振。等待完成(真);
等待颤音。说话(_newVoiceText!);
}
}
Future\u stop()异步{
var result=等待颤振tts.stop();
如果(结果==1)设置状态(()=>ttsState=ttsState.stopped);
}
Future\u pause()异步{
var result=等待颤振tts.pause();
如果(结果==1)设置状态(()=>ttsState=ttsState.paused);
}
@凌驾
无效处置(){
super.dispose();
停下来();
}
列表getLanguageDropDownMenuItems(){
var项目=[];
for(语言中的动态类型){
add(DropdownMenuItem(值:类型为字符串,子项:文本(类型));
}
退货项目;
}
void changedLanguageDropDownItem(字符串?selectedType){
设置状态(){
语言=所选类型;
setLanguage(语言!);
if(isAndroid){
颤振
.isLanguageInstalled(语言!)
.然后((值)=>isCurrentLanguageInstalled=(值为bool));
}
});
}
void\u onChange(字符串文本){
设置状态(){
_newVoiceText=文本;
});
}
@凌驾
小部件构建(构建上下文){
返回材料PP(
家:脚手架(
appBar:appBar(
标题:文本(“颤振TTS”),
),
正文:SingleChildScrollView(
滚动方向:轴垂直,
子项:列(子项:[
_inputSection(),
ttsState==ttsState.playing
?_textFromInput(开始、结束)
:文本(“”),
_btnSection(),
语言!=null?\u languageDropDownSection():Text(“”),
_buildSliders()
]))));
}
Widget\u inputSection()=>容器(
对齐:alignment.topCenter,
填充:仅限边设置(顶部:25.0,左侧:25.0,右侧:25.0),
孩子:TextField(
onChanged:(字符串值){
_onChange(值);
开始=0;
end=value.length;
},
));
小部件_textFromInput(int开始,int结束)=>容器(
对齐:alignment.topCenter,
填充:仅限边设置(顶部:25.0,左侧:25.0,右侧:25.0),
孩子:RichText(
textAlign:textAlign.center,
text:TextSpan(子项:[
TextSpan(
文本:_newVoiceText!=null&&start!=0
?\u newVoiceText!。子字符串(0,开始)
: "",
样式:TextStyle(颜色:Colors.black)),
T