如何使用 iOS 7 的 AVSpeechSynthesizer 製作有聲書(1)

來源:互聯網
上載者:User

標籤:style   http   color   使用   strong   os   

原文: http://www.raywenderlich.com/64623/make-narrated-book-using-avspeechsynthesizer-ios-7

隨著 PageViewController 的引入,蘋果讓開發人員們製作圖書類app 更加輕鬆。不幸的是,對於生活在朝九晚五繁忙節奏中的人們來說,閱讀也是一件奢侈的事情。為什麼你不能在讀一本小說的同時做其他事情呢?

在 Siri 剛開始出現的時候,蘋果曾經用複雜的動態文本閱讀將開發人員拒之門外,但當iOS7 發布的時候,蘋果終於放開了這扇大門。

在本教程中,你將製作一本故事書。這本書的每一頁都會在顯示文字的同時朗讀文字中的內容。有聲的閱讀將讓你的 app 在 iTunes 中顯得與眾不同,同時還保護了視力。有聲書尤其受廣播聽眾的喜愛,因為它允許人們在鍛煉、烹飪或工作的同時進行“閱讀”。

當你製作自己的有聲書時, 你將學習到:

  • 如何使用 AVSpeechSynthesizer 和 AVSpeechUtterance 讓 iOS 裝置朗讀文本
  • How to make this synthesized speech sound more natural by modifying AVSpeechUtterance properties like pitch and rate.
  • 如何修改 AVSpeechUtterance 屬性例如 pitch 和 rate,使合成的語音更自然

AVSpeechSynthesizer當然比不上真人語音,但它對於你將要開發的 app 來說,相對容易一些。

注意:關於如何用 Sprite Kit 開發iPad兒童書籍,請參考Tammy Coron 的教程: How to Create an Interactive Children’s Book for the iPad

開始:AVSpeechSynthesizer

首先,請下載 初始項目。進入NarratedBookUsingAVSpeechStarter 目錄,雙擊 NarratedBookUsingAVSpeech.xcodeproj 以開啟初始項目。

Build & run 。你將在模擬器中看到:

書的內容是關於松鼠的童謠。雖然不是亞馬遜買得最火的讀物,但對於本教程來說足夠了。向左滑動進行向後翻頁,向右滑動則返回前一頁。噢,它已經擁有了基本的“書”的功能,真是不錯的開始。

理解機制

注意:教程的最後,會留給你幾個習題。接下來一節將包括樣本項目的一些內容,以便你能獨立完成這些習題。如果你對這部分內容不感興趣,請跳到下一節。

初始項目包括兩個類:

1. Models: 用於存放書籍的內容,它是page 的集合。
2. Presentation: 將 models 展現到螢幕並響應使用者動作(例如滑動手勢)。

在你製作自己的圖書時,理解這兩個類的工作機制是很有必要的。開啟RWTBook.h:

@interface RWTBook : NSObject  

//1

@property (nonatomic, copy, readonly) NSArray *pages;  

//2

+ (instancetype)bookWithPages:(NSArray*)pages;

//3

+ (instancetype)testBook;  

@end

  1. pages 屬性存放了 Page 對象的數組,每個 Page對象代表圖書中的每一頁。
  2. bookWithPages: 方法是一個初始化 Book 的方法,它用指定的 page 對象數組為參數,返回一個 book 對象。
  3. testBook 建立 Book 對象,用於測試。在開始加入和讀取你自己的圖書內容之前,就先使用 testBook 建立一個簡單的 Book 吧。

RWTPage.h聲明如下:

//1

extern NSString* const RWTPageAttributesKeyUtterances;

extern NSString* const RWTPageAttributesKeyBackgroundImage;  

@interface RWTPage : NSObject  

//2

@property (nonatomic, strong, readonly) NSString *displayText;

@property (nonatomic, strong, readonly) UIImage *backgroundImage;  

//3 + (instancetype)pageWithAttributes:(NSDictionary*)attributes;

@end

  1. 常量用於從字典中檢索頁。RWTPageAttributesKeyUtterances常量可以檢索出page 對象中的文本,RWTPageAttributesKeyBackgroundImage則用於檢索 page 對象所用的背景圖片。
  2. displayText 屬性用於儲存 page 的文本,backgroundImage 屬性用於儲存 page 的背景圖片。
  3. pageWithAttributes:用指定的 NSDictionary 建立一個 page 執行個體。

 

RWTPageViewController.m聲明如下:

#pragma mark - Class Extension  

// 1

@interface RWTPageViewController ()

@property (nonatomic, strong) RWTBook *book;

@property (nonatomic, assign) NSUInteger currentPageIndex;

@end  

@implementation RWTPageViewController  

#pragma mark - Lifecycle  

// 2

- (void)viewDidLoad {

   [super viewDidLoad];

   [self setupBook:[RWTBook testBook]];

   UISwipeGestureRecognizer *swipeNext = [[UISwipeGestureRecognizer alloc]                                           initWithTarget:self                                                   action:@selector(gotoNextPage)];

   swipeNext.direction = UISwipeGestureRecognizerDirectionLeft;   [self.view addGestureRecognizer:swipeNext];

   UISwipeGestureRecognizer *swipePrevious = [[UISwipeGestureRecognizer alloc]                                               initWithTarget:self                                                       action:@selector(gotoPreviousPage)];

   swipePrevious.direction = UISwipeGestureRecognizerDirectionRight;

   [self.view addGestureRecognizer:swipePrevious];

}  

#pragma mark - Private  

// 3

- (RWTPage*)currentPage {

   return [self.book.pages objectAtIndex:self.currentPageIndex];

}  

// 4

- (void)setupBook:(RWTBook*)newBook {

   self.book = newBook;

   self.currentPageIndex = 0;

   [self setupForCurrentPage];

}  

// 5

- (void)setupForCurrentPage {

   self.pageTextLabel.text = [self currentPage].displayText;

   self.pageImageView.image = [self currentPage].backgroundImage;

}  

// 6

- (void)gotoNextPage {

   if ([self.book.pages count] == 0 ||

self.currentPageIndex == [self.book.pages count] - 1) {

     return;  

   }  

   self.currentPageIndex += 1;

   [self setupForCurrentPage];

}  

// 7

- (void)gotoPreviousPage {

   if (self.currentPageIndex == 0) {

     return;

   }

   self.currentPageIndex -= 1;

   [self setupForCurrentPage];

}

@end

以上代碼說明如下:

  1. book 屬性儲存了當前的 RWTBook 對象,currentPageIndex屬性儲存了 RWTBook 對象的當前頁索引。
  2. 當視圖載入完畢,設定要顯示的 page,並添加滑動手勢的辨識器以便使用者能通過手勢進行翻頁。
  3. 返回當前頁的 RWTPage 對象。
  4. 設定 book 屬性並將當前頁置為第一頁。
  5. 設定當前頁的顯示內容。
  6. 尋找下一頁,如果該頁存在,則將下一頁設定為當前頁。該方法由 swipeNext 手勢辨識器調用。
  7. 尋找上一頁,如果該頁存在,則將上一頁設定為當前頁。該方法由 swipePrevious 手勢辨識器調用。

播放和停止!

這是一個很要命的問題。

開啟RWTPageViewController.m,在#import "RWTPage.h" 下面加入:

@import AVFoundation;

iOS 語音功能由 AVFoundation 架構提供,你必須匯入這個架構。

提示: @import會匯入並串連 AVFoundation 架構。關於 iOS7 中 @import 及相關的 O-C 語言新特性,請參考這篇文章What’sNew in Objective-C and Foundation in iOS 7。

在 currentPageIndex 屬性聲明之下加入:

@property (nonatomic, strong) AVSpeechSynthesizer *synthesizer;

synthesizer 對象將用於朗讀每一頁中的文字。

可以將 ViewController 中定義的AVSpeechSynthesizer 對象想象成一個會說話的人。而 AVSpeechUtterance 則可以想象成一張小紙條,把紙條遞給這個人,則他就會念出紙條上的字。

注意:一個 AVSpeechUtterance 可能是一個單詞,比如“Whisky”,或者是一個完整的語句,比如“Whisky,frisky,hippidityhop”。

在 RWTPageViewController.m 的最後加入以下方法:

#pragma mark - Speech Management  

- (void)speakNextUtterance {

   AVSpeechUtterance *nextUtterance = [[AVSpeechUtterance alloc]                                        initWithString:[self currentPage].displayText];

   [self.synthesizer speakUtterance:nextUtterance];

}

建立了一個 utterance 對象,然後告訴 synthesizer 去念出它。

然後實現這個方法:

- (void)startSpeaking {

   if (!self.synthesizer) {

     self.synthesizer = [[AVSpeechSynthesizer alloc] init];

   }

     [self speakNextUtterance];

}

這個方法負責初始化 synthesizer 屬性(如果它未初始化的話)。然後調用speakNextUtterance 方法,開始朗讀。

在 viewDidLoad 、gotoNextPage  和 gotoPreviousPage 方法的最後加上這行:

[self startSpeaking];

這樣,當書一開啟,或者使用者前後翻頁的時候,朗讀就會開始。

Build & run,你會聽到AVSpeechSynthesizer 發出的天籟之音。

注意:如果你什麼也沒聽到,請檢查 Mac 或者 iOS 裝置的音量設定(看你是在什麼地方運行這個 app 的)。你可以嘗試著進行翻頁看是不是能播放語音。

提示:如果你是在模擬器上運行程式, 可能控制台會輸出一堆莫名其妙的錯誤資訊。這隻會在模擬器上出現,使用裝置時則不會列印這些錯誤。

如果你聽到了語音播放,請再次 Build & Run。這次,在第一頁內容播放完之前,嘗試向左滑動(向後翻頁)。發現了什嗎?

synthesizer 只會在第一頁念完之後才開始念下一頁。這不是使用者想要的結果,他們會想讓第一頁停止播放而第二頁立即開始。這點小瑕疵對於一頁內容比較短的童謠來說不成問題,但試想一下,如果每頁的內容都很長的話會是什麼效果……


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.