swiftPractice[23]_打字說話 APP
練習:AVSpeechSynthesizer, UISlider, Delegate
顧名思義!懶得說話的時候專用的簡易APP!
APP 功能
● 唸出 textView 輸入的文字
● 利用 slider 控制講話的速度、音調、音量
● 利用 label 顯示 slider 的數值
● 加入兩種講話的 segments
● 重置設定的按鈕
● 自由選擇背景顏色
拆解!
<拆解目錄>
1.畫面規劃、拉 IBOutlet & IBAction
2.設定初始畫面
3.IBAction 功能一:speak(_ sender: UITapGestureRecognizer)
• AVSpeechSynthesizer、AVSpeechUtterance
• 選擇語言的 UISegmentedControl
• 在說完話後執行任務的 AVSpeechSynthesizerDelegate
4.IBAction 功能二:adjustBackground(_ sender: UIButton)
5.IBAction 功能三:adjustSlider(_ sender: UISlider)
• 更新顯示數值 func updateUI()
6.IBAction 功能四:reset(_ sender: UIButton)
7.按空白處收鍵盤
1. 畫面規劃、拉 IBOutlet & IBAction
@IBOutlet weak var speakTextView: UITextView!
@IBOutlet weak var languageSegments: UISegmentedControl!
@IBOutlet weak var speakImageView: UIImageView!
@IBOutlet weak var speedSlider: UISlider!
@IBOutlet weak var pitchSlider: UISlider!
@IBOutlet weak var volumeSlider: UISlider!
@IBOutlet weak var speedLabel: UILabel!
@IBOutlet weak var pitchLabel: UILabel!
@IBOutlet weak var volumeLabel: UILabel!
2. 設定初始畫面
設定介面初始狀態、各Slider區間與預設值,並更新數值 Label
//設置起始畫面
override func viewDidLoad() {
super.viewDidLoad()
speakTextView.text = ""
//設定TextView圓角
speakTextView.layer.cornerRadius = 10
//隱藏表示說話狀態的Icon
speakImageView.isHidden = true
//背景顏色
view.backgroundColor = UIColor(red: 238/255, green: 222/255, blue: 173/255, alpha: 1)
//設定各Slider區間與預設值
speedSlider.minimumValue = 0
speedSlider.maximumValue = 1
speedSlider.value = 0.5
pitchSlider.minimumValue = 0.5
pitchSlider.maximumValue = 2
pitchSlider.value = 1
volumeSlider.minimumValue = 0
volumeSlider.maximumValue = 1
volumeSlider.value = 1
updateUI()
}
✽ 發現:UITextField 有的 PlaceHolder 功能,UITextView 沒有。
3.IBAction 功能一:speak(_ sender: UITapGestureRecognizer)
將 UITapGestureRecognizer 加到狗狗圖上,點按狗狗可以念出輸入框的文字、並顯示代表說話中的 Icon 動畫。
<功能一完整程式碼>
@IBAction func speak(_ sender: UITapGestureRecognizer) {
//顯示表示說話狀態的Icon
speakImageView.isHidden = false
//設置說話內容、速度、音調、音量
let utterance = AVSpeechUtterance(string: speakTextView.text)
utterance.rate = speedSlider.value
utterance.pitchMultiplier = pitchSlider.value
utterance.volume = volumeSlider.value
//判斷語言Segments,預設值為中文
switch languageSegments.selectedSegmentIndex{
case 0: utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
case 1: utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
default: utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
}
//設置代理人
synthesizer.delegate = self
synthesizer.speak(utterance)
}
• AVSpeechSynthesizer、AVSpeechUtterance
先在 function 外宣告合成器,避免來不及在 function 跑完前講完話的狀況
let synthesizer = AVSpeechSynthesizer()
在 AVSpeechUtterance 輸入 TextView 的內容,再將各個 Slider 得到的數值分別存入 rate(速度)、pitchMultiplier(音調)、volume(音量),最後在將 utterance 傳入合成器的 .speak( ) 中,就可以開始說話了!
//設置說話內容
let utterance = AVSpeechUtterance(string: speakTextView.text)
//速度
utterance.rate = speedSlider.value
//音調
utterance.pitchMultiplier = pitchSlider.value
//音量
utterance.volume = volumeSlider.value
synthesizer.speak(utterance)
• 選擇語言的 UISegmentedControl
utterance 有另一個 .voice 的功能用來設定說話語言,可以用 SegmentedControl 搭配 switch case 分別設定每個 segment 對應到的設定。
//判斷語言Segments,預設值為中文
switch languageSegments.selectedSegmentIndex{
//繁體中文
case 0: utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
//英文
case 1: utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
default: utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
}
• 在說完話後執行任務的 AVSpeechSynthesizerDelegate
為了讓動畫能在說話的時候才顯現,我們可以透過 AVSpeechSynthesizerDelegate 的 didFinish功能設定說話結束後移除動畫。
- 首先要讓 Controller 遵從 Delegate
✽ 利用 extension 將需要定義的功能獨立出來,可以減少 Controller 裝太多東西變得雜亂!
extension TalkViewController:AVSpeechSynthesizerDelegate{
}
2. 設定合成器的代理人是 self, 也就是 TalkViewController
synthesizer.delegate = self
3. 在 didFinish 的功能裡設定說完話後,將說話 Icon 隱藏
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
speakImageView.isHidden = true
}
4. IBAction 功能二:adjustBackground(_ sender: UIButton)
設置一個按鈕連接到 UIColorPickerViewController,讓使用者直接選擇背景顏色。
使用 present 將 Controller 顯示出來。
<功能二完整程式碼>
//調整背景顏色功能
@IBAction func adjustBackground(_ sender: UIButton) {
//宣告生成一個選顏色的controller
let controller = UIColorPickerViewController()
//設置代理人
controller.delegate = self
//顯示controller
present(controller, animated: true)
}
★★為了知道使用者選了什麼顏色,並在選完後設定背景,我們需要借用UIColorPickerViewControllerDelegate 裡 didSelect 的功能。
- 先讓 TalkViewController 遵從 Delegate
extension TalkViewController: UIColorPickerViewControllerDelegate{
}
2. 設置 UIColorPickerViewController 的代理人為 self,也就是 TalkViewController
controller.delegate = self
3. 在有 didSelect 的功能裡設定背景顏色為 .selectedColor(被選擇的顏色)
func colorPickerViewController(_ viewController: UIColorPickerViewController, didSelect color: UIColor, continuously: Bool) {
view.backgroundColor = viewController.selectedColor
}
5. IBAction 功能三:adjustSlider(_ sender: UISlider)
將三個 Slider 拉進同一個 IBAction ,目的為偵測使用者是否有調整,另外設置一個 function 來更新數值到對應的 Label 中。
//偵測Slider變動
@IBAction func adjustSlider(_ sender: UISlider) {
updateUI()
}
• 更新顯示數值 func updateUI( )
使用 「 %.1f 」 指定取數值到小數點後一位,並轉為字串存入對應的 Label。
//更新Label數值
func updateUI(){
let speedValue = speedSlider.value
let pitchValue = pitchSlider.value
let volumeValue = volumeSlider.value
speedLabel.text = String(format: "%.1f", speedValue)
pitchLabel.text = String(format: "%.1f", pitchValue)
volumeLabel.text = String(format: "%.1f", volumeValue)
}
6. IBAction 功能四:reset(_ sender: UIButton)
重置按鈕,讓畫面回到初始畫面
//重設數值功能
@IBAction func reset(_ sender: UIButton) {
viewDidLoad()
}
7. 按空白處收鍵盤
呼叫 touchesEnded 並設定 .endEditing( ) 為 true 來關閉鍵盤。
//按空白處收鍵盤
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
APP Demo(有聲音)
完整程式碼
import UIKit
import AVFoundation
class TalkViewController: UIViewController{
//宣告聲音合成器
let synthesizer = AVSpeechSynthesizer()
@IBOutlet weak var speakTextView: UITextView!
@IBOutlet weak var languageSegments: UISegmentedControl!
@IBOutlet weak var speakImageView: UIImageView!
@IBOutlet weak var speedSlider: UISlider!
@IBOutlet weak var pitchSlider: UISlider!
@IBOutlet weak var volumeSlider: UISlider!
@IBOutlet weak var speedLabel: UILabel!
@IBOutlet weak var pitchLabel: UILabel!
@IBOutlet weak var volumeLabel: UILabel!
//設置起始畫面
override func viewDidLoad() {
super.viewDidLoad()
speakTextView.text = ""
speakTextView.layer.cornerRadius = 10
//隱藏表示說話狀態的Icon
speakImageView.isHidden = true
//背景顏色
view.backgroundColor = UIColor(red: 238/255, green: 222/255, blue: 173/255, alpha: 1)
//設定各Slider區間與預設值
speedSlider.minimumValue = 0
speedSlider.maximumValue = 1
speedSlider.value = 0.5
pitchSlider.minimumValue = 0.5
pitchSlider.maximumValue = 2
pitchSlider.value = 1
volumeSlider.minimumValue = 0
volumeSlider.maximumValue = 1
volumeSlider.value = 1
updateUI()
}
//更新Label數值
func updateUI(){
let speedValue = speedSlider.value
let pitchValue = pitchSlider.value
let volumeValue = volumeSlider.value
speedLabel.text = String(format: "%.1f", speedValue)
pitchLabel.text = String(format: "%.1f", pitchValue)
volumeLabel.text = String(format: "%.1f", volumeValue)
}
//按空白處收鍵盤
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
//點狗狗開始說話功能
@IBAction func speak(_ sender: UITapGestureRecognizer) {
//顯示表示說話狀態的Icon
speakImageView.isHidden = false
//設置說話內容、速度、音調、音量
let utterance = AVSpeechUtterance(string: speakTextView.text)
utterance.rate = speedSlider.value
utterance.pitchMultiplier = pitchSlider.value
utterance.volume = volumeSlider.value
//判斷語言Segments,預設值為中文
switch languageSegments.selectedSegmentIndex{
case 0: utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
case 1: utterance.voice = AVSpeechSynthesisVoice(language: "en-US")
default: utterance.voice = AVSpeechSynthesisVoice(language: "zh-TW")
}
//設置代理人
synthesizer.delegate = self
synthesizer.speak(utterance)
}
//調整背景顏色功能
@IBAction func adjustBackground(_ sender: UIButton) {
//宣告生成一個選顏色的controller
let controller = UIColorPickerViewController()
//設置代理人
controller.delegate = self
//顯示controller
present(controller, animated: true)
}
//偵測Slider變動
@IBAction func adjustSlider(_ sender: UISlider) {
updateUI()
}
//重設數值功能
@IBAction func reset(_ sender: UIButton) {
viewDidLoad()
}
}
//遵從需要的Protocol、定義Function
extension TalkViewController: UIColorPickerViewControllerDelegate, AVSpeechSynthesizerDelegate{
func colorPickerViewController(_ viewController: UIColorPickerViewController, didSelect color: UIColor, continuously: Bool) {
view.backgroundColor = viewController.selectedColor
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
speakImageView.isHidden = true
}
}
後記
藉輕鬆可愛的小作業練習 protocol、delegate、extension 大魔王😊頓時也變得沒那麼兇猛了~(?下一題!
作業出處
GitHub