22. TextReader 朗读与语音交互
本章导读
语音交互是儿童教育类应用的核心能力之一。「柚兔学伴」中,诗词朗读、汉字发音、提醒音效等场景均通过 HarmonyOS SpeechKit 的 TextReader 与第三方 SXPlayer 两套方案实现。本章将详解它们的集成方式与实战用法。
22.1 TextReader 初始化
TextReader 是 HarmonyOS@kit.SpeechKit提供的系统级朗读控件,使用前必须在 UIAbility 的onCreate生命周期中完成初始化。
// EntryAbility.etsimport{TextReader}from'@kit.SpeechKit';import{BusinessError}from'@ohos.base';exportdefaultclassEntryAbilityextendsUIAbility{asynconCreate(want:Want,launchParam:AbilityConstant.LaunchParam):Promise<void>{if(this.context){constreaderParams:TextReader.ReaderParam={isVoiceBrandVisible:true,businessBrandInfo:{panelName:'小艺朗读',panelIcon:$r('app.media.startIcon')}};awaitTextReader.init(this.context,readerParams).then(()=>{console.info(`TextReader succeeded in initializing.`);}).catch((e:BusinessError)=>{console.error(`TextReader failed to initialize. Code:${e.code}, message:${e.message}`);})}}}关键参数说明:
| 参数 | 类型 | 作用 |
|---|---|---|
isVoiceBrandVisible | boolean | 是否在朗读面板显示语音品牌标识 |
businessBrandInfo.panelName | string | 朗读面板标题,如"小艺朗读" |
businessBrandInfo.panelIcon | Resource | 朗读面板图标资源 |
初始化必须在onCreate中完成,不能延迟到页面加载阶段,否则后续TextReader.start()调用会失败。
22.2 PoemReader 朗读工具类
为方便多处复用,项目将 TextReader 的调用封装为静态工具类PoemReader:
// PoemReader.etsimport{TextReader}from"@kit.SpeechKit";import{BusinessError}from"@kit.BasicServicesKit";exportclassPoemReader{staticplay(poem:string,title:string='',author:string='',date?:string){constreadInfoList:TextReader.ReadInfo[]=[{id:'001',title:{text:title,isClickable:true},author:{text:author,isClickable:true},date:{text:date??newDate().toISOString().split('T')[0],isClickable:false},bodyInfo:poem}];conststartParams:TextReader.StartParams={isMinibarHidden:true,callbackParam:'0'};TextReader.start(readInfoList,undefined,startParams).then(()=>{console.info(`TextReader succeeded in starting`);}).catch((e:BusinessError)=>{console.error(`TextReader failed to start. Code:${e.code}, message:${e.message}`);});}}ReadInfo 数据结构:
interfaceReadInfo{id:string;// 朗读内容唯一标识title:{text:string;isClickable:boolean};// 标题,可点击跳转author:{text:string;isClickable:boolean};// 作者,可点击跳转date:{text:string;isClickable:boolean};// 日期,不可点击bodyInfo:string;// 朗读正文内容}StartParams 参数:
| 参数 | 说明 |
|---|---|
isMinibarHidden | 是否隐藏迷你朗读条(true 则全屏朗读面板) |
callbackParam | 回调参数,用于标识本次朗读请求 |
设计要点:isClickable控制朗读面板中对应区域是否可交互。对于诗词场景,标题和作者可点击查看详情,日期设为不可点击。
22.3 三大使用场景
场景一:PoemPage 诗词播读
在诗词详情页,点击"播读"按钮调用朗读:
// PoemPage.ets@BuilderbuildBottom(){Row(){Button('播读').layoutWeight(1).borderRadius(5).linearGradient({angle:90,colors:[[0xFF33FF,0.0],[0x8E44FF,1]]}).onClick(()=>{PoemReader.play(this.poemInfo?.poem??'');})Blank(10)Button('下一首').layoutWeight(1).borderRadius(5).linearGradient({angle:90,colors:[[0x8E44FF,0.0],[0x1C55FF,1]]}).onClick(()=>{this.generatePoem()})}.width('100%').padding(10)}此处只传入诗词正文,标题、作者使用默认空值。朗读面板会以全屏模式展示。
场景二:StrokeView 汉字发音
在笔画查询页面,点击 Canvas 区域即可听到当前汉字的读音:
// StrokeView.etsCanvas(this.context!!).width(100).height(100).onReady(()=>{this.canvasReady=true;if(!this.isLoading){this.initializeCanvas();this.strokeManager.startAnimation(this.context!!,()=>{this.updateAnimationInfo();});}}).onClick(()=>{PoemReader.play(this.word);})this.word是单个汉字(如"样"),TextReader 会自动识别并朗读该字的发音,非常适合儿童识字场景。
场景三:TodoView 诗词卡片朗读
在首页待办视图中,点击诗词卡片触发朗读:
// TodoView.etsColumn({space:12}){Text(this.poem).fontFamily('kaiti').fontWeight(FontWeight.Bold).textAlign(TextAlign.Center).lineSpacing(LengthMetrics.fp(18))}.margin({left:12}).justifyContent(FlexAlign.Center).mainCardStyle().onClick(()=>{PoemReader.play(this.poem);})诗词内容来自每日推荐,用户轻触即可聆听朗读,实现"看诗即听"的沉浸体验。
22.4 SXPlayer 自定义音频播放
对于非朗读类的音频需求(如计时结束提醒音),项目使用@qtfm/smartxplayer模块的 SXPlayer:
初始化与回调
// TodoView.etsimport{AudioEntry,PlayActionCallback,PlayParams,SXPlayer}from'@qtfm/smartxplayer';constcontext:common.UIAbilityContext=GlobalUIAbilityContext.getContext()@Componentexportstruct TodoView{privatecallback:PlayActionCallback={onPlayPrevious:()=>{},onPlayNext:()=>{},onToggleFavorite:(assetId)=>{}}privatesxplayer:SXPlayer=newSXPlayer(context,{enableLog:true,bundleName:"com.youtoo.study.partner",abilityName:"EntryAbility",playActionCallback:this.callback})}播放提醒音
倒计时结束时,读取 rawfile 中的铃声文件并播放:
onTimerFinished=async()=>{this.alarmVisible=trueletfileDescriptor=awaitcontext.resourceManager.getRawFd("ringtone_youtoo.mp3");letentity:AudioEntry={fd:fileDescriptor}letparams:PlayParams={audioEntry:[entity],playWhenPrepared:true,hasPrevious:false,hasNext:false,isLive:false}this.sxplayer!.play(params)}PlayParams 参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
audioEntry | AudioEntry[] | 音频数据源,支持 fd 文件描述符 |
playWhenPrepared | boolean | 准备就绪后自动播放 |
hasPrevious | boolean | 是否有上一首 |
hasNext | boolean | 是否有下一首 |
isLive | boolean | 是否为直播流 |
smartxplayer 模块导出
export{SXPlayer,SXWorkerPlayer,SXBaseAudioPlayer,SXCastPlayer,ISXAudioPlayer}- SXPlayer:标准播放器,适合短音频播放
- SXWorkerPlayer:Worker 线程播放器,避免阻塞 UI
- SXBaseAudioPlayer:基础播放器抽象类
- SXCastPlayer:投播播放器
- ISXAudioPlayer:播放器接口定义
22.5 两套方案对比与选型建议
| 对比维度 | TextReader | SXPlayer |
|---|---|---|
| 适用场景 | 文本朗读(诗词、汉字) | 音频文件播放(铃声、音乐) |
| 输入类型 | 文本字符串 | 文件描述符(fd) |
| 系统依赖 | SpeechKit | 第三方模块 |
| 朗读面板 | 内置 UI 面板 | 无 UI,纯后台播放 |
| 个性化 | 支持品牌信息定制 | 支持播放控制回调 |
选型原则:
- 需要系统级朗读 UI + 文本转语音 → TextReader
- 需要播放预置音频文件 + 自定义控制逻辑 → SXPlayer
- 两者可共存,互不冲突
本章小结
本章介绍了「柚兔学伴」中语音交互的完整实现方案。TextReader 在 EntryAbility.onCreate 中初始化,通过 PoemReader 工具类在诗词页、笔画页、首页卡片三处统一调用;SXPlayer 则负责计时提醒等纯音频播放场景。两者各司其职,共同构建了应用的语音交互体系。下一章将介绍字帖生成与 PDF 导出功能。