Skip to content

Instantly share code, notes, and snippets.

@minsOne
Forked from Snowy1803/ContentView.swift
Created July 28, 2023 01:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save minsOne/e628818791e20a0e4d1ef21cfe848837 to your computer and use it in GitHub Desktop.
Save minsOne/e628818791e20a0e4d1ef21cfe848837 to your computer and use it in GitHub Desktop.
This code allows you to use matchedGeometryEffect in SwiftUI while keeping iOS 13 compatibility in your app.

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

//
// 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()
}
}
//
// 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)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment