Skip to content

Instantly share code, notes, and snippets.

@ggrell
Forked from Snowy1803/ContentView.swift
Created February 12, 2021 22:16
Show Gist options
  • Save ggrell/8a72199a4185e12dd6d05cab4703ac4b to your computer and use it in GitHub Desktop.
Save ggrell/8a72199a4185e12dd6d05cab4703ac4b 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