【SwiftUI】エクセサイズ用にカウントで筋トレメニューの指示を読み上げるアプリを自作する | Apple iOS 開発 YouTube セミナー 44


Swift5.1.3 Xcode11.3.1 SwiftUI


- 筋トレアプリを作り残り時間を定期的に喋らせる
- タイマーと読み上げ機能を連携させる
- SwiftUIでAVSpeechUtteranceとTimerを使う


残り時間をカウントして筋トレやフィットネスなどルーチンワークの指示をアプリが教えます


「以下は動画のハイライトです。」

制限時間を決めて筋トレを行うと効果的です。ラストスパートなど残り時間がわかるといいですね。

アプリを自分で作れば自在にiPhoneをトレーナーの用に喋らせることができます。事前に決めた筋トレメニューを一定の間隔で読み上げさせることなどお手の物です。

その作り方を今回お伝えします。

本動画はYouTubeセミナー第20回のカウントダウンの機能と第37回のテキスト読み上げ機能を連携させます。

こちらの動画をご覧になられていない方はまずそちらを参照してから本動画をご査収いただくようお願いいたします。細かい説明は割愛させていただきます。

まずテキストエリアに自由に文字を書けるアプリを作ってみましょう。
AVFoundationをimportしたら以下のStructを記述します。


import AVFoundation

struct TextArea: UIViewRepresentable {
@Binding var text: String

func makeUIView(context: Context) -> UITextView {

let myTextArea = UITextView()
myTextArea.delegate = context.coordinator
myTextArea.font = UIFont(name: "HelveticaNeue", size: 25)
myTextArea.backgroundColor = UIColor(displayP3Red: 0.8, green: 0.8, blue: 1.0, alpha: 0.2)

return myTextArea
}

func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
}

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

class Coordinator : NSObject, UITextViewDelegate {

var parent: TextArea

init(_ uiTextView: TextArea) {
self.parent = uiTextView
}

func textViewDidChange(_ textView: UITextView) {
self.parent.text = textView.text
}
}
}



このテキストエリアに記述されたテキストが後にロボットに読み上げられることとなります。使い方はContentView内に以下を設定してください。


TextArea(
text: $text
).frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)



この変数textが読み上げ元のテキスト情報となります。作動させる時は以下のfunctionを使用します。


func txtSpeech (spText:String) {

let utterance = AVSpeechUtterance(string: spText)
utterance.voice = AVSpeechSynthesisVoice(language: "en-US")

utterance.rate = 0.5

let synthesizer = AVSpeechSynthesizer()
if synthesizer.isSpeaking == false {
synthesizer.speak(utterance)
print("speak", spText)
}

}



このfunctionをTimerViewのStructの中に埋め込みます。全体的には以下のようになります。


struct TimerView : View {

@State var nowDate: Date = Date()

let setDate: Date
@Binding var text: String

var timer: Timer {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {_ in
self.nowDate = Date()
}
}

var body: some View {
Text(TimerFunction(from: setDate))
.onAppear(perform: {
self.timer
})

}

func txtSpeech (spText:String) {

let utterance = AVSpeechUtterance(string: spText)
utterance.voice = AVSpeechSynthesisVoice(language: "ja-JP")

utterance.rate = 0.55

let synthesizer = AVSpeechSynthesizer()
if synthesizer.isSpeaking == false {
synthesizer.speak(utterance)
print("speak", spText)
}

}

func TimerFunction(from date: Date) -> String {

let calendar = Calendar(identifier: .gregorian)
let timeValue = calendar.dateComponents([.second], from: nowDate, to: setDate)

var ctStr = ""
if timeValue.second! > 0 {
ctStr = String(format: "%d",timeValue.second!)
}


if Int(ctStr) != nil {
switch Int(ctStr)! {
case 1:
txtSpeech(spText: self.text)
case 5:
txtSpeech(spText: "5秒前")
case 10:
txtSpeech(spText: "10秒前")
default:
print("default")
}
}

return ctStr

}

}



変数ctStrはカウントダウンによる残りの秒数を示します。この秒数が所定の残り時間になった時にswithでふるい分けて所定の文言を喋らせるという仕組みとなります。

ここまでできたらあとはContentView内でボタン仕掛けで筋トレを開始するだけです。value: 12を変えることでカウントダウンの秒数を変更できます。


Button(action: {
self.spechWrok = true
self.toDate = Calendar.current.date(byAdding: .second, value: 12, to: Date())!
}) {
Text("筋トレ開始")
}

if spechWrok == true {
TimerView(setDate: toDate, text: self.$text)
}




YouTube動画の方では色々な言葉をiPhoneにタイマー仕掛けで喋らせてみたいと思います。


ソースコードはYouTubeのコメント欄に記載します。

目次へ戻る

2020年02月07日