Site icon AppTractor

Делаем в SwiftUI размытие экрана при переключении задачи

Повышение конфиденциальности пользователей имеет решающее значение при разработке приложений. В этом руководстве рассказывается о том, как создать приложение SwiftUI, которое автоматически размывает экран, когда переходит в многозадачный или фоновый режим, — полезная функция защиты конфиденциального контента.

Мы рассмотрим, как реализовать эту концепцию на шутливом примере с «секретами» разработчика, которые размываются, когда приложение не активно. Следуя этому краткому пошаговому руководству, вы узнаете, как применить эту технику защиты конфиденциальности в своих приложениях SwiftUI.

Прежде чем начать

Прежде чем начать, убедитесь, что вы обладаете базовыми знаниями о Swift и SwiftUI, особенно об управлении сценами и фазами сцен. Если вы не знакомы с этими понятиями, рекомендуем вам ознакомиться с документацией Apple по SwiftUI.

Настройка проекта

Чтобы продемонстрировать размытие экрана, мы воспользуемся простым приложением под названием My Secrets, которое скрывает конфиденциальную информацию, когда приложение переходит в фоновый режим.

В качестве отправной точки создайте список секретов, хранящихся локально, чтобы заполнить наш пользовательский интерфейс.

class SecretsStore {
    
    static var secrets: [String] = [
        "I still have a soft spot for **UIKit**.",
        "I cringe at the sight of hamburger menus.",
        "In **Human Interface Guidelines**, I trust.",
        "I secretly enjoy writing documentation.",
        "I believe every bug is just a misunderstood feature",
        "I'm always looking for a better way to do things.",
        "I have a favorite Xcode theme, and it's not dark..."
    ]
    
}

Затем обновите ContentView, чтобы отобразить простой стилизованный список элементов массива секретов из SecretsStore.

struct ContentView: View {
    
    var body: some View {
        List(SecretsStore.secrets, id: \.self) { secret in
            Text(.init(secret))
                .listRowSeparator(.hidden)
                .fontDesign(.monospaced)
        }
        .listStyle(.inset)
        .navigationTitle("My Secrets")
    }
    
}

Задача приложения — автоматически размывать содержимое при переходе в режим многозадачности или при бездействии. Вот как мы можем это реализовать.

Размытие представления

В ContentView.swift приложение будет отслеживать состояние сцены с помощью @Environment(\.scenePhase), чтобы определить, когда оно становится неактивным или переходит в фоновый режим. В зависимости от текущего состояния сцены будет меняться значение радиуса размытия, применяемого к содержимому представления.

struct ContentView: View {
    // Monitoring the value of the scenePhase from the app environment
    @Environment(\.scenePhase) private var scenePhase
    // Value of the radius of the blur effect
    @State private var blurRadius: CGFloat = 0
    
    var body: some View {
        NavigationStack {
            List(SecretsStore.secrets, id: \.self) { secret in
                Text(.init(secret))
                    .listRowSeparator(.hidden)
                    .fontDesign(.monospaced)
            }
            .listStyle(.inset)
            .navigationTitle("My Secrets")
        }
        // Changes the blurRadius value when the scene phase changes
        .onChange(of: scenePhase) { oldPhase, newPhase in
            if newPhase == .inactive || newPhase == .background {
                withAnimation { blurRadius = 20}
            } else {
                withAnimation { blurRadius = 0}
            }
        }
        
    }
}

Затем с помощью модификатора blur(radius:opaque:) мы применим эффект размытия к содержимому View.

struct ContentView: View {
    // Monitoring the value of the scenePhase from the app environment
    @Environment(\.scenePhase) private var scenePhase
    // Value of the radius of the blur effect
    @State private var blurRadius: CGFloat = 0
    
    var body: some View {
        NavigationStack {
            List(SecretsStore.secrets, id: \.self) { secret in
                Text(.init(secret))
                    .listRowSeparator(.hidden)
                    .fontDesign(.monospaced)
            }
            .listStyle(.inset)
            .navigationTitle("My Secrets")
            
            // The blur modifier
            .blur(radius: blurRadius)
            
        }
        // Changes the blurRadius value when the scene phase changes
        .onChange(of: scenePhase) { oldPhase, newPhase in
            if newPhase == .inactive || newPhase == .background {
                withAnimation { blurRadius = 20}
            } else {
                withAnimation { blurRadius = 0}
            }
        }
        
    }
}

Если пользователь переключается на другое приложение или возвращается на главный экран, конфиденциальный контент в вашем приложении становится размытым, скрывая его от глаз. Таким образом, отображаемая информация остается защищенной, когда приложение неактивно.

Когда пользователь возвращается к вашему приложению, эффект размытия плавно исчезает, делая содержимое снова видимым без резких переходов.

Расширяем функцию

Хотя в предыдущем примере речь шла об одном представлении, вы можете расширить функциональность размытия на все приложение, интегрировав аналогичную логику в делегат главной сцены вашего приложения или выше в иерархии представлений. Это гарантирует, что весь конфиденциальный контент останется защищенным при переходе приложения из одного состояния в другое.

import SwiftUI

@main
struct MySecretsApp: App {

    @Environment(\.scenePhase) private var scenePhase
    @State private var blurRadius: CGFloat = 0

    var body: some Scene {
    
        WindowGroup {
        
            ZStack {
                ContentView()
                    .blur(radius: blurRadius)
                    
                if blurRadius > 0 {
                    Image("logo")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 200)
                }
            }
            
            .onChange(of: scenePhase) { oldValue, newValue in
                if newValue == .inactive || newValue == .background {
                    withAnimation { blurRadius = 20 }
                } else {
                    withAnimation { blurRadius = 0 }
                }
            }
            
        }
        
    }
}

Создание контейнера

Другим подходом может быть создание контейнера представлений, который будет отвечать за отслеживание текущего состояния приложения и применение эффекта размытия к его содержимому. Это может быть полезно, если вы хотите поместить изображение поверх содержимого, например логотип приложения, или если есть только определенные View, которые вы хотите размыть.

struct SensitiveContentView<Content: View>: View {
    
    @Environment(\.scenePhase) private var scenePhase
    @State private var blurRadius: CGFloat = 0
    
    private var content: Content
    
    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }
    
    var body: some View {
        
        ZStack {
            content
                .blur(radius: blurRadius)
            
            // Shows the app logo on top of the blurred content
            if blurRadius != 0 {
                Image(systemName: "swift")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width: 200)
            }
            
        }
        
        .onChange(of: scenePhase) { oldPhase, newPhase in
            if newPhase == .inactive || newPhase == .background {
                withAnimation { blurRadius = 20 }
            } else {
                withAnimation { blurRadius = 0 }
            }
        }
        
    }
}

Та же логика может быть использована для создания пользовательского модификатора.

Источник

Exit mobile version