ios电子书语音阅读

非常感谢大家利用自己宝贵的时间来阅读我的文章 ,  上一篇文章写了Epub的加密一个实现方式,《ios Epub加密及解密阅读的一种实现方式》,今天这篇文章主要说一下电子书的语音阅读,这个功能也基本上是阅读器的标配了。希望这篇文章能给你的开发过程带来一些帮助。喜欢的可以关注一下我的简书我的博客   

先看下效果图,声音没法展示,下载ZQReaderDemo运行看效果吧



关于电子书阅读这这块就不说了,还是在XDSReader的基础上修改,添加了语音阅读的功能

在网上查了些资料,IOS7.0之后系统添加了文字转语音的API,AVFoundation框架下的AVSpeechSynthesizer,具体使用代码如下,也可参考ZQReaderDemo中的ZQAVSpeechTool

//初始化语音合成器
        _avSpeaker = [[AVSpeechSynthesizer alloc] init];
        _avSpeaker.delegate = self;
        //初始化要说出的内容
        AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:_paragraphs[_currentParagraphs]];
        //设置语速,语速介于AVSpeechUtteranceMaximumSpeechRate和AVSpeechUtteranceMinimumSpeechRate之间
        //AVSpeechUtteranceMaximumSpeechRate
        //AVSpeechUtteranceMinimumSpeechRate
        //AVSpeechUtteranceDefaultSpeechRate
        utterance.rate = _rate;
        
        //设置音高,[0.5 - 2] 默认 = 1
        //AVSpeechUtteranceMaximumSpeechRate
        //AVSpeechUtteranceMinimumSpeechRate
        //AVSpeechUtteranceDefaultSpeechRate
        utterance.pitchMultiplier = 1;
        
        //设置音量,[0-1] 默认 = 1
        utterance.volume = 1;
        
        //读一段前的停顿时间
        utterance.preUtteranceDelay = 0.5;
        //读完一段后的停顿时间
        utterance.postUtteranceDelay = 0;
        
        //设置声音,是AVSpeechSynthesisVoice对象
        //AVSpeechSynthesisVoice定义了一系列的声音, 主要是不同的语言和地区.
        //voiceWithLanguage: 根据制定的语言, 获得一个声音.
        //speechVoices: 获得当前设备支持的声音
        //currentLanguageCode: 获得当前声音的语言字符串, 比如”ZH-cn”
        //language: 获得当前的语言
        //通过特定的语言获得声音
        AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
        //通过voicce标示获得声音
        //AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithIdentifier:AVSpeechSynthesisVoiceIdentifierAlex];
        utterance.voice = voice;
        //开始朗读
        [_avSpeaker speakUtterance:utterance];

既然语音转文字实现方法找到了,那么剩下的都是逻辑上的问题了,最后整理了一下实现思路,用户在阅读菜单上点击语音按钮,开始语音阅读当前页内容,首先取出当前页的所有文本,当前页读完跳转下一页继续阅读,后考虑到高亮问题,又把每一页的文本拆分成段落进行阅读,当读完一段开始读下一段,当前页读完就继续读下一页,当前章读完就读下一章,整体思路想好了就开整。

1、创建了一个单例工具类ZQAVSpeechTool,代码如下

.h

#import <Foundation/Foundation.h>

@interface ZQAVSpeechTool : NSObject

+(instancetype)shareSpeechTool;

//开始朗读
- (void)speechTextWith:(NSString *)text;
//暂停朗读
- (void)pauseSpeech;
//继续朗读
- (void)continueSpeech;
//结束朗读
- (void)StopSpeech;
//切换语速
- (void)changeRate:(CGFloat)rate;


@end

.m

#import "ZQAVSpeechTool.h"
#import <AVFoundation/AVFoundation.h>

@interface ZQAVSpeechTool ()<AVSpeechSynthesizerDelegate>

@property (nonatomic ,strong)AVSpeechSynthesizer *avSpeaker;

@property (nonatomic ,strong)NSArray *paragraphs;

@property (nonatomic ,assign)NSInteger currentParagraphs;


@property (nonatomic ,assign)CGFloat rate;


@end

@implementation ZQAVSpeechTool

// 单例
+(instancetype)shareSpeechTool {
    static ZQAVSpeechTool *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[ZQAVSpeechTool alloc]init];
        
    });
    return instance;
}

- (void)speechTextWith:(NSString *)text
{
    if (!(text.length>0)) {
        return;
    }
    if (_avSpeaker) {
        //把每一页文字拆分成段
        _paragraphs =[text componentsSeparatedByString:@"\n"];
        _currentParagraphs = 0;
        [self speechParagraphWith:_paragraphs[_currentParagraphs]];
    }else
    {
        //初次阅读
        NSUserDefaults *useDef = [NSUserDefaults standardUserDefaults];
        _rate = [useDef floatForKey:@"speechRate"];
        if (!_rate) {
            _rate = 0.5;
        }
        _paragraphs =[text componentsSeparatedByString:@"\n"];
        _currentParagraphs = 0;
         [[NSNotificationCenter defaultCenter] postNotificationName:@"speechParagraph" object:_paragraphs[_currentParagraphs]];
        //初始化语音合成器
        _avSpeaker = [[AVSpeechSynthesizer alloc] init];
        _avSpeaker.delegate = self;
        //初始化要说出的内容
        AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:_paragraphs[_currentParagraphs]];
        //设置语速,语速介于AVSpeechUtteranceMaximumSpeechRate和AVSpeechUtteranceMinimumSpeechRate之间
        //AVSpeechUtteranceMaximumSpeechRate
        //AVSpeechUtteranceMinimumSpeechRate
        //AVSpeechUtteranceDefaultSpeechRate
        utterance.rate = _rate;
        
        //设置音高,[0.5 - 2] 默认 = 1
        //AVSpeechUtteranceMaximumSpeechRate
        //AVSpeechUtteranceMinimumSpeechRate
        //AVSpeechUtteranceDefaultSpeechRate
        utterance.pitchMultiplier = 1;
        
        //设置音量,[0-1] 默认 = 1
        utterance.volume = 1;
        
        //读一段前的停顿时间
        utterance.preUtteranceDelay = 0.5;
        //读完一段后的停顿时间
        utterance.postUtteranceDelay = 0;
        
        //设置声音,是AVSpeechSynthesisVoice对象
        //AVSpeechSynthesisVoice定义了一系列的声音, 主要是不同的语言和地区.
        //voiceWithLanguage: 根据制定的语言, 获得一个声音.
        //speechVoices: 获得当前设备支持的声音
        //currentLanguageCode: 获得当前声音的语言字符串, 比如”ZH-cn”
        //language: 获得当前的语言
        //通过特定的语言获得声音
        AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
        //通过voicce标示获得声音
        //AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithIdentifier:AVSpeechSynthesisVoiceIdentifierAlex];
        utterance.voice = voice;
        //开始朗读
        [_avSpeaker speakUtterance:utterance];
    }
                                    
}

- (void)speechParagraphWith:(NSString *)Paragraph
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"speechParagraph" object:Paragraph];
    AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:Paragraph];
    utterance.rate = _rate;
    [_avSpeaker speakUtterance:utterance];
}
//切换语速
- (void)changeRate:(CGFloat)rate
{
    _rate = rate;
    //
    [_avSpeaker stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];    //初始化语音合成器
//    _avSpeaker = [[AVSpeechSynthesizer alloc] init];
//    _avSpeaker.delegate = self;
    AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:_paragraphs[_currentParagraphs]];
    utterance.rate = rate;
    utterance.pitchMultiplier = 1;
    utterance.volume = 1;
    utterance.preUtteranceDelay = 0.5;
    utterance.postUtteranceDelay = 0;
    
    
    [_avSpeaker speakUtterance:utterance];
    NSUserDefaults *useDef = [NSUserDefaults standardUserDefaults];
    [useDef setFloat:rate forKey:@"speechRate"];
    [useDef synchronize];
    
}

- (void)pauseSpeech
{
    //暂停朗读
    //AVSpeechBoundaryImmediate 立即停止
    //AVSpeechBoundaryWord    当前词结束后停止
    [_avSpeaker pauseSpeakingAtBoundary:AVSpeechBoundaryImmediate];
}

- (void)continueSpeech
{
    [_avSpeaker continueSpeaking];
    
}

- (void)StopSpeech
{
    //AVSpeechBoundaryImmediate 立即停止
    //AVSpeechBoundaryWord    当前词结束后停止
    [_avSpeaker stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
    _avSpeaker = nil;
    [XDSReadManager sharedManager].speeching = NO;
     [[NSNotificationCenter defaultCenter] postNotificationName:@"speechDidStop" object:nil];

}

#pragma mark -
#pragma mark - AVSpeechSynthesizerDelegate
//已经开始
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didStartSpeechUtterance:(AVSpeechUtterance *)utterance{
   
    
}
//已经说完
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance{
    
    
   
    _currentParagraphs+=1;
    if (_currentParagraphs<_paragraphs.count) {
         //读下一段
        [self speechParagraphWith:_paragraphs[_currentParagraphs]];
    }else{
    
    
    NSInteger currentPage = CURRENT_RECORD.currentPage;
    NSInteger currentChapter = CURRENT_RECORD.currentChapter;
    if (currentPage < CURRENT_RECORD.totalPage - 1) {
        //下一页
        currentPage += 1;
    }else
    {
        if (currentChapter < CURRENT_RECORD.totalChapters - 1) {
            //下一章
            currentChapter += 1;
            currentPage = 0;
        }else
        {
            //全书读完
            [self StopSpeech];
            return;
        }
        
    }
    
    [[XDSReadManager sharedManager] readViewJumpToChapter:currentChapter page:currentPage];
     NSString *content = CURRENT_RECORD.chapterModel.pageStrings[currentPage];
    [self speechTextWith:content];
    
    }
    
}



//已经暂停
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didPauseSpeechUtterance:(AVSpeechUtterance *)utterance{
    
}
//已经继续说话
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didContinueSpeechUtterance:(AVSpeechUtterance *)utterance{
    
}
//已经取消说话
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didCancelSpeechUtterance:(AVSpeechUtterance *)utterance{
    
}
//将要说某段话
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer willSpeakRangeOfSpeechString:(NSRange)characterRange utterance:(AVSpeechUtterance *)utterance{
    
//    DebugLog(@"%@",utterance.speechString);
    
}

@end

2、为XDSReadManager添加开始语音阅读的方法,并添加一个用于判断当前阅读状态的属性

- (void)begainSpeech;

@property (nonatomic ,assign)BOOL speeching;

方法的实现

//开始语音阅读
- (void)begainSpeech
{
    //取出当前页文字内容
    XDSChapterModel *currentChapterModel = _bookModel.record.chapterModel;
    NSInteger currentPage = _bookModel.record.currentPage;
    NSString *content = currentChapterModel.pageStrings[currentPage];
    //开始朗读本页文字
    [[ZQAVSpeechTool shareSpeechTool] speechTextWith:content];
    self.speeching = YES;
    
}

3、在弹出菜单时判断是否正在朗读,是则弹出语音阅读菜单ZQSpeechMenuView,因为AVSpeechSynthesizer只有女声,所以菜单只是加了调节语速和暂停/播放、退出的功能,没有添加切换男女声的功能

主要功能实现

//暂停/播放
- (void)pauseBtnClick:(UIButton *)sender
{
    if (_pauseBtn.selected) {
        [[ZQAVSpeechTool shareSpeechTool] continueSpeech];
    }else{
        [[ZQAVSpeechTool shareSpeechTool] pauseSpeech];
    }
    _pauseBtn.selected = !_pauseBtn.selected;
}

//退出
- (void)stopBtnClick
{
    _pauseBtn.selected = NO;
    [[ZQAVSpeechTool shareSpeechTool] StopSpeech];
    [self removeFromSuperview];
}

//切换语速
- (void)sliderValueChanged:(UISlider *)slider{
    
    [[ZQAVSpeechTool shareSpeechTool] changeRate:slider.value];
    _pauseBtn.selected = NO;
}

4、高亮正在阅读段落

- (void)highlightTextWith:(NSString *)text{
    
    //移除上一段背景色
    if (_currentRange.length>0) {
        [_readAttributedContent removeAttribute:NSBackgroundColorAttributeName range:_currentRange];
    }
    //设置当前朗读段落背景色
    NSRange range = [_content rangeOfString:text];
    _currentRange = range;
    [_readAttributedContent addAttribute:NSBackgroundColorAttributeName value:RGB(150, 220, 240) range:range];
    self.readAttributedContent = _readAttributedContent;
    [self reloadView];
}

大工搞成,具体的实现逻辑及代码见ZQReaderDemo,语音菜单界面约束使用的SDAutoLayout,可以根据自己习惯进行更改。





 

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaozhaoqiang/article/details/80348895
上一篇ios Epub加密及解密阅读的一种实现方式
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭