はじめに
PCの場合、一定時間操作がないとスクリーンセーバーが起動します。
そのような挙動を再現したかったのですが、公式のAPIにはなさそうだったので自作してみました。
サンプルアプリ
色々迷った結果、このようなアプリにしました。
画面を放置していると画像を非表示にします。
仕様
監視するスクリーンの範囲は.onTimeout()
を付けているViewの大きさです。
実装
import SwiftUI
public extension View {
func onTimeout(seconds: TimeInterval = 30, perform: ((ScreenStates) -> Void)?) -> some View {
Timeout(content: self, seconds: seconds) { status in
if let perform {
perform(status)
}
}
}
}
public enum ScreenStates {
case active
case timeout
}
fileprivate struct Timeout<T: View>: View {
var content: T
var seconds: TimeInterval
var perform: ((ScreenStates) -> Void)
@State var timer: Timer? = nil
@State var states: ScreenStates = .timeout
var body: some View {
content
.onTapGesture {
start()
}
.onAppear {
start()
}
.onDisappear {
stop()
}
}
private func changeScreenStatus(status: ScreenStates) {
if self.states != status {
states = status
perform(status)
}
}
private func start() {
changeScreenStatus(status: .active)
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: seconds, repeats: false) { _ in
changeScreenStatus(status: .timeout)
}
}
private func stop() {
timer?.invalidate()
}
}
使い方
import SwiftUI
struct ContentView: View {
@State var isScreenHidden: Bool = false
private let url = "https://avatars.githubusercontent.com/u/84154073"
var body: some View {
ZStack {
Color(uiColor: .systemGroupedBackground).ignoresSafeArea()
VStack(spacing: 5) {
if isScreenHidden {
Image(systemName: "lock.fill")
Text("一定時間操作がなかったため、画面を非表示にしました")
} else {
AsyncImage(url: URL(string: url)!)
}
}
}
.onTimeout(seconds: 5) { status in
switch status {
case .active:
withAnimation { isScreenHidden = false }
case .timeout:
withAnimation { isScreenHidden = true }
}
}
}
}
引数のseconds
でタイムアウトになる時間を設定します。
おわり
ライブラリにしたのでスターください!
これからアップデートする予定です!