Snippets
VisionOS: AccessoryView or Ornament in SwiftUI, depending on the target OS.
public struct EditorView: View {
public var body: some View {
EditTextView(text: .constant("Hello, World!"))
#if os(visionOS)
.ornament(attachmentAnchor: .scene(.bottom)) {
Button("Done") { }
#else
.safeAreaInset(edge: .bottom) {
Button("Done") { }
}
#endif
}
}
TabView with custom binding for side effects on tab selection
struct RootView: View {
enum Tab: Int, CaseIterable {
case home, notifications, search, profile
}
@State private var selectedTab: Tab = .home
TabView(selection: .init(get: {
selectedTab
}, set: { newTab in
if newTab == .post {
appRouterPath.presentedSheet = .newStatusEditor(visibility: userPreferences.postVisibility)
return
}
HapticManager.shared.fireHaptic(.tabSelection)
SoundEffectManager.shared.playSound(.tabSelection)
selectedTab = newTab
})) {
ForEach(Tab.allCases, id: \.self) { tab in
tab.makeContentView()
.tabItem {
tab.label
}
.tag(tab)
}
}
}
Async Transferable for ShareLink
struct AsyncImageTransferable: Codable, Transferable {
let url: URL
func fetchData() async -> Data {
do {
return try await URLSession.shared.data(from: url).0
} catch {
return Data()
}
}
static var transferRepresentation: some TransferRepresentation {
DataRepresentation(exportedContentType: .jpeg) { transferable in
await transferable.fetchData()
}
}
}
struct ShareView: View {
let imageURL: URL
var body: some View {
let transferable = AsyncImageTransferable(url: imageURL)
ShareLink(item: transferable, preview: .init("Share this image", image: transferable))
}
}
Access AppDelegate from SwiftUI App
@main
struct IceCubesApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegatern
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool
{
print("Application did finish lauching")
}
}
Programmatic navigation with NavigationStack
public enum RouterDestination: Hashable {
case accountDetail(id: String)
}
@MainActor
extension View {
func withAppRouter() -> some View {
navigationDestination(for: RouterDestination.self) { destination in
switch destination {
case let .accountDetail(id):
AccountDetailView(accountId: id)
}
}
}
}
@MainActor
public class RouterPath: ObservableObject {
@Published public var path: [RouterDestination] = []
public func navigate(to: RouterDestination) {
path.append(to)
}
}
struct NotificationsTab: View {
@StateObject private var routerPath = RouterPath()
var body: some View {
NavigationStack(path: $routerPath.path) {
Button("Navigate to account") {
routerPath.navigate(to: .accountDetail(id: accountId))
}
.withAppRouter()
}
}
}
Sheet with visual effect / blurred background and corner radius
public struct AppAccountsSelectorView: View {
@State private var isPresented: Bool = false
public var body: some View {
Button {
isPresented.toggle()
} label: {
Text("Present sheet")
}
.sheet(isPresented: $isPresented) {
accountsView
.presentationDetents([.height(preferredHeight), .large])
.presentationBackground(.thinMaterial)
.presentationCornerRadius(16)
}
}
}
Save array of Codable in @AppStorage
extension Array: RawRepresentable where Element: Codable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode([Element].self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
}
Minimal SwiftUI + SwiftData app
@Model
final class Thread {
@Attribute(.unique) var id: UUID
var createdOn: Date
var content: String
var author: User
var isLiked: Bool = false
init(content: String, author: User) {
self.id = UUID()
self.createdOn = Date()
self.content = content
self.author = author
}
}
@Model
final class User {
@Attribute(.unique) var id: UUID
var username: String
init(username: String) {
self.id = UUID()
self.username = username
}
}
Creating and using custom Environment values in SwiftUI
public extension EnvironmentValues {
var isSecondaryColumn: Bool {
get { self[SecondaryColumnKey.self] }
set { self[SecondaryColumnKey.self] = newValue }
}
}
public struct NotificationsTab: View {
public var body: some View {
NotificationsListView()
.environment(\.isSecondaryColumn, true)
}
}
public struct NotificationsListView: View {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
public var body: some View {
if isSecondaryColumn {
Text("I'm secondary column")
} else {
Text("I'm not secondary column")
}
}
}
2024 © Thomas Ricouard.