[SwiftUI] Viewにアニメーション付きプレースホルダーモディファイアを追加

画像説明

使い方


// `isLoading: Bool` 変数を準備します。
VStack { ... }
    .redacted(reason: viewModel.isLoading ? .placeholder : [])
    .animatePlaceholder(isLoading: $isLoading)

全画面モードに入る 全画面モードを終了する


2ステップ


  1. AnimatePlaceholderModifierを作る
  2. Viewに拡張メソッドを追加する

ステップ1: AnimatePlaceholderModifierを作る

struct AnimatePlaceholderModifier: AnimatableModifier {
    @Binding var isLoading: Bool

    @State private var isAnim: Bool = false
    private var center = (UIScreen.main.bounds.width / 2) + 110
    private let animation: Animation = .linear(duration: 1.5)

    init(isLoading: Binding<Bool>) {
        self._isLoading = isLoading
    }

    func body(content: Content) -> some View {
        content.overlay(animView.mask(content))
    }

    var animView: some View {
        ZStack {
            Color.black.opacity(isLoading ? 0.09 : 0.0)
            Color.white.mask(
                Rectangle()
                    .fill(
                        LinearGradient(gradient: .init(colors: [.clear, .white.opacity(0.48), .clear]), startPoint: .top , endPoint: .bottom)
                    )
                    .scaleEffect(1.5)
                    .rotationEffect(.init(degrees: 70.0))
                    .offset(x: isAnim ? center : -center)
            )
        }
        .animation(isLoading ? animation.repeatForever(autoreverses: false) : nil, value: isAnim)
        .onAppear {
            guard isLoading else { return }
            isAnim.toggle()
        }
        .onChange(of: isLoading) { _ in
            isAnim.toggle()
        }
    }
}

全画面モードに入る 全画面モードを終了する

ステップ2: Viewに拡張メソッドを追加する

extension View {
    func animatePlaceholder(isLoading: Binding<Bool>) -> some View {
        self.modifier(AnimatePlaceholderModifier(isLoading: isLoading))
    }
}

全画面モードに入る 全画面モードを終了する

こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/shohe/swiftui-animate-placeholder-modifier-for-view-5d06