Skip to content

Instantly share code, notes, and snippets.

@Snowy1803
Last active December 31, 2024 11:53
Show Gist options
  • Select an option

  • Save Snowy1803/c077b60190c2543a823526a0c73ff142 to your computer and use it in GitHub Desktop.

Select an option

Save Snowy1803/c077b60190c2543a823526a0c73ff142 to your computer and use it in GitHub Desktop.

Revisions

  1. Snowy1803 revised this gist Oct 16, 2020. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    # NamespaceWrapper

    This gist allows you tu use `matchedGeometryEffect` in SwiftUI 1, with an iOS 13 deployment target. iOS 13 users will get a fade animation, while iOS 14 users can get a beautiful matched geometry effect.

    Instead of making a `@Namespace`, just use the `.namespaced()` modifier in your common view, and instead of `.matchedGeometryEffect`, use `.namespacedMatchedGeometryEffect`. All the namespace handling is done in `.namespaced()`, so you don't pass a `Namespace.ID` to your effect modifier.

    The only missing property is the `properties` argument. It can be added pretty easily, by using its `rawValue` as argument (because its type is iOS 14-only).
  2. Snowy1803 created this gist Oct 16, 2020.
    40 changes: 40 additions & 0 deletions ContentView.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,40 @@
    //
    // ContentView.swift
    // Example of using matchedGeometryEffect in iOS 13 code
    // matchedGeometryEffect example code taken and adapted from :
    // https://sarunw.com/posts/a-first-look-at-matchedgeometryeffect/
    //
    // Created by Emil Pedersen on 16/10/2020.
    //

    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()
    }
    }
    69 changes: 69 additions & 0 deletions NamespaceWrapper.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    //
    // NamespaceWrapper.swift
    // NamespaceWrapper for using matchedGeometryEffect in iOS 13 code
    //
    // Created by Emil Pedersen on 16/10/2020.
    //

    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)
    }
    }
    }