100 Days of SwiftUI(DAY 87(Project17 part 2))

2020.09.04
今日は、AppleのCombineフレームワークを使用した通知の監視について学習します。コードは非常にシンプルで、説明はほとんど必要ありません。それでも、システムイベントのあらゆる種類の監視を行うことができます。

タイマーを使用して繰り返しイベントをトリガーする
SwiftUIアプリがバックグラウンドに移動したときに通知を受ける方法
SwiftUIによる特定のアクセシビリティニーズのサポート

タイマーを使用して繰り返しイベントをトリガーする
Triggering events repeatedly using a timer

import SwiftUI

struct ContentView: View {
    //let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    let timer = Timer.publish(every: 1, tolerance: 0.5, on: .main, in: .common).autoconnect()
    @State private var counter = 0

    var body: some View {
        Text("Hello, World!")
            .onReceive(timer) { time in
                if self.counter == 5 {
                    self.timer.upstream.connect().cancel()
                } else {
                    print("The time is now \(time)")
                }

                self.counter += 1
            }
    }
}

SwiftUIアプリがバックグラウンドに移動したときに通知を受ける方法
How to be notified when your SwiftUI app moves to the background

Combine(組み合わせ)

UIApplication.willResignActiveNotification
アプリがバックグラウンドに移行し始めたときに通知センターからメッセージが送信される。
willEnterForegroundNotification
アプリを再度アクティブ化
userDidTakeScreenshotNotification
ユーザーがスクリーンショットを撮ったことを検出する
UIApplication.significantTimeChangeNotification ユーザーが時計を変更したとき、または夏時間が変更されたときに呼び出されます。
UIResponder.keyboardDidShowNotification キーボードが表示されているときに呼び出されます。

import SwiftUI

struct ContentView: View {

    var body: some View {
        VStack{
            Text("Hello, World!")
            .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
                print("Moving to the background!")
            }
            
            Text("Hello, World!")
            .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
                print("Moving back to the foreground!")
            }
            
            Text("Hello, World!")
            .onReceive(NotificationCenter.default.publisher(for: UIApplication.userDidTakeScreenshotNotification)) { _ in
                print("User took a screenshot!")
            }
        }
    }
}


通常のレイアウトに単純な緑の背景を使用していますが、色なしで区別が有効になっている場合は、黒の背景を使用してチェックマークを追加します。

struct ContentView: View {
    @Environment(\.accessibilityDifferentiateWithoutColor) var differentiateWithoutColor
    var body: some View {
        HStack {
            if differentiateWithoutColor {
                Image(systemName: "checkmark.circle")
            }

            Text("Success")
        }
        .padding()
        .background(differentiateWithoutColor ? Color.black : Color.green)
        .foregroundColor(Color.white)
        .clipShape(Capsule())
    }
}

SwiftUIによる特定のアクセシビリティニーズのサポート
Supporting specific accessibility needs with SwiftUI

accessibilityDifferentiateWithoutColor「色なしで区別する」
通常のレイアウトに単純な緑の背景を使用していますが、色なしで区別が有効になっている場合は、黒の背景を使用してチェックマークを追加します。

accessibilityReduceMotion
もう1つの一般的なオプションは、モーションの削減です。


import SwiftUI

struct ContentView: View {
    @Environment(\.accessibilityReduceTransparency) var reduceTransparency
    var body: some View {
        Text("Hello, World!")
            .padding()
            .background(reduceTransparency ? Color.black : Color.black.opacity(0.5))
            .foregroundColor(Color.white)
            .clipShape(Capsule())
    }
}
/*
struct ContentView: View {
    @Environment(\.accessibilityReduceMotion) var reduceMotion
    @State private var scale: CGFloat = 1

    var body: some View {
        Text("Hello, World!")
            .scaleEffect(scale)
            .onTapGesture {
                if self.reduceMotion {
                    self.scale *= 1.5
                } else {
                    withAnimation {
                        self.scale *= 1.5
                    }
                }
            }
    }
}
*/
/*
func withOptionalAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
    if UIAccessibility.isReduceMotionEnabled {
        return try body()
    } else {
        return try withAnimation(animation, body)
    }
}

struct ContentView: View {
    @Environment(\.accessibilityReduceMotion) var reduceMotion
    @State private var scale: CGFloat = 1
    

    var body: some View {
        Text("Hello, World!")
        .scaleEffect(scale)
        .onTapGesture {
            withOptionalAnimation {
                self.scale *= 1.5
            }
        }
    }
}
*/
/*
struct ContentView: View {
    @Environment(\.accessibilityDifferentiateWithoutColor) var differentiateWithoutColor
    var body: some View {
        HStack {
            if differentiateWithoutColor {
                Image(systemName: "checkmark.circle")
            }

            Text("Success")
        }
        .padding()
        .background(differentiateWithoutColor ? Color.black : Color.green)
        .foregroundColor(Color.white)
        .clipShape(Capsule())
    }
}
*/