Instantly share code, notes, and snippets.
Created
June 10, 2022 08:27
-
Star
8
(8)
You must be signed in to star a gist -
Fork
3
(3)
You must be signed in to fork a gist
-
Save Dimillian/c10ffac65a1a37b337a07b5cf0773cea to your computer and use it in GitHub Desktop.
An example on how to use the new NavigationSplitView on iPad with global navigation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
enum HomeDestination: String, CaseIterable, Hashable { | |
case hot, best, trending, new, top, rising | |
} | |
enum SubredditDestination: String, CaseIterable, Hashable { | |
case news, diablo, pics, wtf, games, movies | |
} | |
enum UserDestination: String, CaseIterable, Hashable { | |
case profile, inbox, posts, comments, saved | |
} | |
enum Destination: Hashable { | |
case home(home: HomeDestination) | |
case subreddit(subreddit: SubredditDestination) | |
case user(user: UserDestination) | |
case post(post: Post) | |
} | |
struct MainView: View { | |
@State private var sidebarDestination: Destination = .subreddit(subreddit: .games) | |
@State private var detailNavigation: Destination? | |
var body: some View { | |
NavigationSplitView { | |
SidebarView(destination: $sidebarDestination) | |
} content: { | |
switch sidebarDestination { | |
case .home(let destination): | |
HomeView(destination: destination) | |
case .subreddit(let subreddit): | |
SubredditView(subreddit: subreddit, destination: $detailNavigation) | |
case .user(let destination): | |
AccountView(destination: destination) | |
case .post(let post): | |
PostView(post: post) | |
} | |
} detail: { | |
NavigationStack { | |
Group { | |
if let detailNavigation { | |
switch detailNavigation { | |
case .post(let post): | |
PostView(post: post) | |
default: | |
Text("Please select a post") | |
} | |
} else { | |
Text("Please select a post") | |
} | |
}.navigationDestination(for: Destination.self) { destination in | |
switch destination { | |
case .user(let userDestination): | |
AccountView(destination: userDestination) | |
default: | |
Text("Not supported here") | |
} | |
} | |
} | |
} | |
} | |
} | |
struct SidebarView: View { | |
@Binding var destination: Destination | |
var body: some View { | |
List(selection: $destination) { | |
Section("Home") { | |
ForEach(HomeDestination.allCases, id: \.self) { homeItem in | |
NavigationLink(value: Destination.home(home: homeItem)) { | |
Label(homeItem.rawValue.capitalized, systemImage: "globe") | |
} | |
} | |
} | |
Section("Subreddit") { | |
ForEach(SubredditDestination.allCases, id: \.self) { subreddit in | |
NavigationLink(value: Destination.subreddit(subreddit: subreddit)) { | |
Label(subreddit.rawValue.capitalized, systemImage: "globe") | |
} | |
} | |
} | |
Section("Account") { | |
ForEach(UserDestination.allCases, id: \.self) { userDestination in | |
NavigationLink(value: Destination.user(user: userDestination)) { | |
Label(userDestination.rawValue.capitalized, systemImage: "globe") | |
} | |
} | |
} | |
} | |
} | |
} | |
struct Post: Identifiable, Hashable { | |
let id = UUID() | |
let title = "A post title" | |
let preview = "Some wall of text to represent the preview of a post that nobody will read if the title is not a clickbait" | |
} | |
struct SubredditView: View { | |
let subreddit: SubredditDestination | |
@Binding var destination: Destination? | |
@State private var posts: [Post] = [Post(), Post(), Post(), Post(), Post(), Post(), Post(), Post()] | |
var body: some View { | |
List(posts, selection: $destination) { post in | |
NavigationLink(value: Destination.post(post: post)) { | |
HStack { | |
VStack(alignment: .leading) { | |
Text(post.title) | |
.font(.title3) | |
.fontWeight(.semibold) | |
Text(post.preview) | |
.font(.callout) | |
} | |
} | |
} | |
}.navigationTitle(subreddit.rawValue.capitalized) | |
} | |
} | |
struct PostView: View { | |
let post: Post | |
var body: some View { | |
VStack { | |
Text(post.title) | |
.font(.title) | |
Text(post.preview) | |
NavigationLink(value: Destination.user(user: .comments)) { | |
Text("See some sub navigation") | |
} | |
} | |
} | |
} | |
struct AccountView: View { | |
let destination: UserDestination | |
var body: some View { | |
Text(destination.rawValue.capitalized) | |
} | |
} | |
struct HomeView: View { | |
let destination: HomeDestination | |
var body: some View { | |
Text(destination.rawValue.capitalized) | |
} | |
} | |
struct MainView_Previews: PreviewProvider { | |
static var previews: some View { | |
MainView() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for posting.
Using
@State
for selection causes this behaviour in .compact class as sidebar and content are recreated.So, persisting the selections (by following Bringing robust navigation structure to your SwiftUI app) seems to resolve the issue.
Also, iOS beta 4 resolved the following issue which required a workaround for conditional views:
Updated code:
https://gist.github.com/nkalvi/4cdc746ab92b5da664621d61ac7690e9