본문 바로가기
카테고리 없음

[SwiftUI] iOS13에서 @Namespace 사용하기

by steady.dev 2021. 11. 1.

@Namespace는 iOS 14에서 새로 생긴 propery wrapper 이다. iOS 13에서 사용하기 위해서는 코드를 사용해야 한다.

 

 

아래와 같이 코드를 작성하고,

더보기
import SwiftUI

@available(iOS 14, *)
struct NamespaceWrapper<Content: View>: View {
    @Namespace var namespace
    
    var content: Content
    
    var body: some View {
        content.environment(\.namespace, namespace)
    }
}

@available(iOS 14, *)
struct NamespaceReader<Content: View, ID: Hashable>: View {
    @Environment(\.namespace) var namespace
    
    var content: Content
    
    var id: ID
    var anchor: UnitPoint = .center
    var isSource: Bool = true
    
    var body: some View {
        content.matchedGeometryEffect(id: id, in: namespace!, anchor: anchor, isSource: isSource)
    }
}

@available(iOS 14, *)
struct NamespaceKey: EnvironmentKey {
    static let defaultValue: Namespace.ID? = nil
}

@available(iOS 14, *)
extension EnvironmentValues {
    var namespace: Namespace.ID? {
        get {
            self[NamespaceKey.self]
        }
        set {
            self[NamespaceKey.self] = newValue
        }
    }
}

extension View {
    func namespaced() -> AnyView {
        if #available(iOS 14, *) {
            return AnyView(NamespaceWrapper(content: self))
        } else {
            return AnyView(self)
        }
    }
    
    func namespacedMatchedGeometryEffect<ID>(id: ID, anchor: UnitPoint = .center, isSource: Bool = true) -> some View where ID : Hashable {
        if #available(iOS 14, *) {
            return AnyView(NamespaceReader(content: self, id: id, anchor: anchor, isSource: isSource))
        } else {
            return AnyView(self)
        }
    }
}

아래와 같이 사용한다.

더보기
struct ContentView: View {
    @State private var isExpanded = false
    
    var body: some View {
        Group {
            if isExpanded {
                VStack {
                    RoundedRectangle(cornerRadius: 10)
                        .foregroundColor(Color.pink)
                        .frame(width: 60, height: 60)
                        .namespacedMatchedGeometryEffect(id: "rect")
                    Text("Hello SwiftUI!").fontWeight(.semibold)
                        .namespacedMatchedGeometryEffect(id: "text")
                }
            } else {
                HStack {
                    Text("Hello SwiftUI!").fontWeight(.semibold)
                        .namespacedMatchedGeometryEffect(id: "text")
                    RoundedRectangle(cornerRadius: 10)
                        .foregroundColor(Color.pink)
                        .frame(width: 60, height: 60)
                        .namespacedMatchedGeometryEffect(id: "rect")
                }
            }
        }.onTapGesture {
            withAnimation {
                isExpanded.toggle()
            }
        }.namespaced()
    }
}

 

출처

https://gist.github.com/Snowy1803/c077b60190c2543a823526a0c73ff142

 

This code allows you to use matchedGeometryEffect in SwiftUI while keeping iOS 13 compatibility in your app.

This code allows you to use matchedGeometryEffect in SwiftUI while keeping iOS 13 compatibility in your app. - ContentView.swift

gist.github.com

 

댓글