如何解决Flutter - 下划线或绘制文字转语音 (TTS)
我有一个 Flutter 程序可以将文本翻译成语音,但我有一个问题,如何在它所说的内容下划线?就是说每一个字都有下划线或画,希望有人能帮帮我,非常感谢。
解决方法
我认为您在具有开始和结束值的 TTS 期间收到了进度回调。只需将文本分成三部分(开始前的部分,开始和结束之间的部分,结束后的部分),并使用适当的注释将它们分配到三个 TextSpan。
,此讨论应该对您有所帮助:https://github.com/dlutton/flutter_tts/discussions/193 以下是该讨论中提供的要点中的代码:
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,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) : "",]),));
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),_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);
},label: "Rate: $rate",activeColor: Colors.green,);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。