LoginSignup
4
2

More than 1 year has passed since last update.

【SwiftUI】Combineを使ってデジタル時計を作る

Last updated at Posted at 2022-11-05

はじめに

以前はTimelineViewでデジタル時計を作成してみました
今回はCombineを使用してデジタル時計を作成してみようと思います。

完成形

Videotogif.gif

完成コード

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を使うと簡潔に記述できて良いです!

完成プロジェクトを置いときます。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2