Develop Apps for iOSをやってみる 〜その10〜
はじめに
DX推進室の野上です。
前回 の続きです。
どこから?
今回はここから続けます。
最初に
今回も用意されたプロジェクトファイルがあります。
このプロジェクトファイルを使うことにします。
Timer Viewの描画
MeetingTimerViewを作成する
MeetingViewのうち、ヘッダーとフッターはそれぞれ切り出したので、
同じようにタイマー部分もMeetingTimerViewとして切り出しましょう。
新しくMeetingTimerView.swiftを作成して、以下のようにします。
import SwiftUI
struct MeetingTimerView: View {
let speakers: [ScrumTimer.Speaker]
let theme: Theme
private var currentSpeaker: String {
speakers.first(where: { !$0.isCompleted })?.name ?? "Someone"
}
var body: some View {
Circle()
.strokeBorder(lineWidth: 24)
.overlay {
VStack {
Text(currentSpeaker)
.font(.title)
Text("is speaking")
}
.accessibilityElement(children: .combine)
.foregroundStyle(theme.accentColor)
}
}
}
struct MeetingTimerView_Previews: PreviewProvider {
static var speakers: [ScrumTimer.Speaker] {
[ScrumTimer.Speaker(name: "Bill", isCompleted: true), ScrumTimer.Speaker(name: "Cathy", isCompleted: false)]
}
static var previews: some View {
MeetingTimerView(speakers: speakers, theme: .yellow)
}
}
MeetingView側も変更します。
import SwiftUI
import AVFoundation
struct MeetingView: View {
@Binding var scrum: DailyScrum
@StateObject var scrumTimer = ScrumTimer()
var player: AVPlayer { AVPlayer.sharedDingPlayer }
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 16.0)
.fill(scrum.color)
VStack {
MeetingHeaderView(secondsElapsed: scrumTimer.secondsElapsed, secondsRemaining: scrumTimer.secondsRemaining, scrumColor: scrum.color)
MeetingTimerView(speakers: scrumTimer.speakers, scrumColor: scrum.color)
MeetingFooterView(speakers: scrumTimer.speakers, skipAction: scrumTimer.skipSpeaker)
}
}
.padding()
.foregroundColor(scrum.color.accessibleFontColor)
.onAppear {
scrumTimer.reset(lengthInMinutes: scrum.lengthInMinutes, attendees: scrum.attendees)
scrumTimer.speakerChangedAction = {
player.seek(to: .zero)
player.play()
}
scrumTimer.startScrum()
}
.onDisappear {
scrumTimer.stopScrum()
let newHistory = History(attendees: scrum.attendees, lengthInMinutes: scrumTimer.secondsElapsed / 60)
scrum.history.insert(newHistory, at: 0)
}
}
}
struct MeetingView_Previews: PreviewProvider {
static var previews: some View {
MeetingView(scrum: .constant(DailyScrum.data[0]))
}
}
MeetingViewの中でCircle()を使って描画していた部分をMeetingTimerView()に差し替えています。
円を描画する
次に、ミテーィング参加者が話している時の何人目かを示す円を描画します。
Shapeプロトコルに準拠したSpeakerArcを作成します。
SpeakerArc.swiftというファイルを作って以下の内容を記述します。
import SwiftUI
struct SpeakerArc: Shape {
let speakerIndex: Int
let totalSpeakers: Int
private var degreesPerSpeaker: Double {
360.0 / Double(totalSpeakers)
}
private var startAngle: Angle {
Angle(degrees: degreesPerSpeaker * Double(speakerIndex) + 1.0)
}
private var endAngle: Angle {
Angle(degrees: startAngle.degrees + degreesPerSpeaker - 1.0)
}
func path(in rect: CGRect) -> Path {
let diameter = min(rect.size.width, rect.size.height) - 24.0
let radius = diameter / 2.0
let center = CGPoint(x: rect.midX, y: rect.midY)
return Path { path in
path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
}
}
}
次にSpeakerArcを使って、ひとり分が終わるたびに円を更新する処理を追加します。
プログレス用のリングを描画する
MeetingTimerViewのCircle()に.overlayでSpeakerArcを描画していきます。
import SwiftUI
struct MeetingTimerView: View {
let speakers: [ScrumTimer.Speaker]
var scrumColor: Color
private var currentSpeaker: String { speakers.first(where: { !$0.isCompleted })?.name ?? "Someone" }
var body: some View {
ZStack {
Circle()
.strokeBorder(lineWidth: 24, antialiased: true)
VStack {
Text(currentSpeaker)
.font(.title)
Text("is speaking")
}
.accessibilityElement(children: .combine)
.foregroundColor(scrumColor.accessibleFontColor)
ForEach(speakers) { speaker in
if speaker.isCompleted,
let index = speakers.firstIndex(where: { $0.id == speaker.id }) {
SpeakerArc(speakerIndex: index, totalSpeakers: speakers.count)
.rotation(Angle(degrees: -90))
.stroke(scrumColor, lineWidth: 12)
}
}
}
.padding(.horizontal)
}
}
struct MeetingTimerView_Preview: PreviewProvider {
@State static var speakers = [ScrumTimer.Speaker(name: "Kim", isCompleted: true), ScrumTimer.Speaker(name: "Bill", isCompleted: false)]
static var previews: some View {
MeetingTimerView(speakers: speakers, scrumColor: Color("Design"))
}
}
アプリを実行して確認してみてください。
ミーティング参加者を先送りするたびに円が更新されていくのがわかると思います。
次回は 音声をテキストに書き出すです。
多分最終回になる・・・はず・・・。