はじめに
以前はTimelineViewでデジタル時計を作成してみました
今回はCombineを使用してデジタル時計を作成してみようと思います。
完成形
完成コード
ContentView.swift
import SwiftUI
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
GeometryReader { geo in
ZStack(alignment: .center) {
Color(red: 132/255, green: 209/255, blue: 78/255).edgesIgnoringSafeArea(.all)
VStack(alignment: .center, spacing: 10) {
Text("\(viewModel.time.formatted(.iso8601.year().month().day().dateSeparator(.dash)))")
.fontWeight(.medium)
.font(.custom("DSEG7Modern-BoldItalic", size: geo.size.width/15))
.foregroundColor(.black)
.background(
Text("8888-88-88")
.fontWeight(.medium)
.font(.custom("DSEG7Modern-BoldItalic", size: geo.size.width/15))
.foregroundColor(.black.opacity(0.1))
)
Text("\(viewModel.time.formatted(.iso8601.time(includingFractionalSeconds: false)))")
.fontWeight(.medium)
.font(.custom("DSEG7Modern-BoldItalic", size: geo.size.width/6))
.foregroundColor(.black)
.background(
Text("88:88:88")
.fontWeight(.medium)
.font(.custom("DSEG7Modern-BoldItalic", size: geo.size.width/6))
.foregroundColor(.black.opacity(0.1))
)
}
}
}
.onDisappear {
viewModel.timer.upstream.connect().cancel()
}
}
}
ViewModel.swift
import Combine
import Foundation
final class ViewModel: ObservableObject {
@Published var time: Date = Date.now
let timer = Timer.publish(every: 1, on: .main, in: .default).autoconnect()
private var cancellables = Set<AnyCancellable>()
init() {
timer
.sink { [weak self] date in
guard let self else { return }
self.time = Date.now
}
.store(in: &cancellables)
}
}
解説
時間の更新
Combineで定期実行をする場合は下記のコードになります
例は1秒間隔でsink
の処理を行います
Timer.publish(every: 1, on: .main, in: .default)
.autoconnect()
.sink { _ in
// 処理
}
.store(in: &cancellables)
@Published
で現在時刻を保管します
@Published var time: Date = Date.now
ViewModelにある現在時刻をView側で呼び出します
Text("\(viewModel.time.formatted(.iso8601.year().month().day().dateSeparator(.dash)))")
Text("\(viewModel.time.formatted(.iso8601.time(includingFractionalSeconds: false)))")
フォント
カスタムフォントを設定しています。
フォントサイズは適当なので各自調整してください。
一応、iPad 11inch, iPhoneSE, iPhone12で正常に表示される事を確認しました
.font(.custom("DSEG7Modern-BoldItalic", size: geo.size.width/15))
文字背景に焼き付きを表示
88を重ねることによってデジタル時計感が増します
.background(
Text("8888-88-88")
.fontWeight(.medium)
.font(.custom("DSEG7Modern-BoldItalic", size: geo.size.width/15))
.foregroundColor(.black.opacity(0.1))
)
おわり
Combineを使うと簡潔に記述できて良いです!
完成プロジェクトを置いときます。