How could I make certain menu items appear depending on the navigation "bar" I press - swift

I am building an app that will store multiple Nintendo consoles and their details (kinda like Mactracker but for Nintendo stuff).
I wanna store certain consoles in categories on the main menu but I'm not sure how I could do it (I'm pretty new to swiftui so sorry if that's a stupid question).
I already have categories set on MainMenu based on the category I've put in my consoles array. But I can't get the console menu (where all the consoles are) to store the consoles only of the category I tap on.
My consoles array has multiple consoles but I've put just one to save space.
Main Menu:
import SwiftUI
struct MainMenu: View {
var con: [ConsoleDetails] = ConsoleList.consoles
var body: some View {
NavigationView{
List(ConsoleList.categories.sorted(by: {$0.key > $1.key}), id:\.key){con in
NavigationLink(destination: ConsoleMenu(), label:{
Image(systemName: "folder.fill")
.scaledToFit()
.frame(height: 30)
.cornerRadius(4)
.padding(.vertical, 4)
VStack{
Text(con.key)
.fontWeight(.semibold)
}
}).navigationTitle("app.name")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
MainMenu()
}
}
ConsoleMenu:
import SwiftUI
struct ConsoleMenu: View {
var con: [ConsoleDetails] = ConsoleList.consoles
var body: some View {
NavigationView{
List(con, id:\.id){ cons in
NavigationLink(destination: ConsoleDetailView(con: cons), label:{
Image(cons.imgName)
.resizable()
.scaledToFit()
.frame(height: 50)
.cornerRadius(4)
.padding(.vertical, 4)
VStack{
Text(cons.consoleName)
.fontWeight(.semibold)
}
}).navigationTitle("\(cons.category)")
}
}
}
}
struct ConsoleSection_Previews: PreviewProvider {
static var previews: some View {
ConsoleMenu()
.preferredColorScheme(.dark)
}
}
Consoles:
import Foundation
struct ConsoleDetails: Identifiable{
let id = UUID()
var imgName: String = ""
var consoleName: String = ""
var description: String = ""
var initialPrice: Double = 0.0
var ReleaseDate: String = ""
var Discontinuation: Int = 0
var category: String = ""
}
struct ConsoleList{
static let categories = Dictionary(grouping: consoles, by: {$0.category } )
static let consoles = [
ConsoleDetails(imgName: "FAMICOM",
consoleName: "Famicom",
description: "It was released in 1983 in Japan and due to it success it gave birth to the NES",
initialPrice: 179,
ReleaseDate: "Release Date: July 15, 1983",
Discontinuation: 2003,
category: "Home Consoles"),
//there's more consoles but I just put one to save space on here

Few modifications:
In main view use only categories and pass only useful consoles to console menu :
struct MainMenu: View {
// Use categories ordered by reversed alphabetical order
var categories = ConsoleList.categories.sorted(by: {$0.key > $1.key})
// var con: [ConsoleDetails] = ConsoleList.consoles
var body: some View {
NavigationView{
// Loop on categories
List(categories, id:\.key){category in
NavigationLink(destination: ConsoleMenu(con: category.value), label:{
Image(systemName: "folder.fill")
.scaledToFit()
.frame(height: 30)
.cornerRadius(4)
.padding(.vertical, 4)
VStack{
Text(category.key)
.fontWeight(.semibold)
}
}).navigationTitle("app.name")
}
}
}
}
In Console menu use the consoles furnished by main menu
struct ConsoleMenu: View {
// Consoles are given by caller
var con: [ConsoleDetails] /* = ConsoleList.consoles */
var body: some View {
NavigationView{
List(con, id:\.id){ cons in
NavigationLink(destination: ConsoleDetailView(con: cons), label:{
Image(cons.imgName)
.resizable()
.scaledToFit()
.frame(height: 50)
.cornerRadius(4)
.padding(.vertical, 4)
VStack{
Text(cons.consoleName)
.fontWeight(.semibold)
}
}).navigationTitle("\(cons.category)")
}
}
}
}

Related

How to update #ObservedObject object while adding items to the class

I have 2 sections (ingredients selection and ingredient added). In the ingredient selection, i get all items from a json file. The goal is whenever i chose an ingredient from the ingredient selection, the item should be added to the ingredient added section. However the actual result is that I am able to add all ingredients in AddedIngredients. However my #ObservedObject var ingredientAdded :AddedIngredients indicates no items, so nothing in the section.
What am I missing in my logic?
Is it because the #Published var ingredients = [Ingredient]() is from a struct which creates a new struct every time ? My understanding is that since AddedIngredients is a class, it should reference the same date unless I override it.
This my model:
import Foundation
struct Ingredient: Codable, Identifiable {
let id: String
let price: String
let ajoute: Bool
}
class AddedIngredients: ObservableObject {
#Published var ingredients = [Ingredient]()
}
The ingredient section that displays all ingredients:
struct SectionIngredientsSelection: View {
let ingredients: [Ingredient]
#StateObject var ajoute = AddedIngredients()
var body: some View {
Section(header: VStack {
Text("Ajouter vos ingredients")
}) {
ForEach(ingredients){ingredient in
HStack{
HStack{
Image("mais")
.resizable()
.frame(width: 20, height: 20)
Text(ingredient.id)
}
Spacer()
HStack{
Text(ingredient.price )
Button(action: {
ajoute.ingredients.append(ingredient)
print(ajoute.ingredients.count)
}){
Image(systemName: "plus")
.foregroundColor(Color(#colorLiteral(red: 0, green: 0.3257463574, blue: 0, alpha: 1)))
}
}
}
}
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
}
}
}
Whenever I add an ingredient from the previous section, it should appear on this section.
struct SectionIngredientsSelected: View {
#ObservedObject var ingredientAdded :AddedIngredients
var body: some View {
Section(header: VStack {
HStack{
Text("Vos ingredients")
.textCase(nil)
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.black)
Button(action: {print(ingredientAdded.ingredients.count)}, label: {Text("Add")})
}
}) {
ForEach(ingredientAdded.ingredients){ingredient in
HStack{
HStack{
Image("mais")
.resizable()
.frame(width: 20, height: 20)
Text(ingredient.id)
}
Spacer()
HStack{
Text(ingredient.price )
Button(action: {
}){
Image(systemName: "xmark.circle")
.foregroundColor(Color(#colorLiteral(red: 0, green: 0.3257463574, blue: 0, alpha: 1)))
}
}
}
}
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
}
}
}
Main View
struct CreationView: View {
let ingredients: [Ingredient] = Bundle.main.decode("Ingredients.json")
var addedIngre: AddedIngredients
var body: some View {
ScrollView {
VStack{
VStack(alignment: .leading) {
Image("creation")
.resizable()
.scaledToFit()
Text("Slectionnez vos ingredients preferes").fontWeight(.light)
Divider()
.padding(.bottom)
}
}
}
List {
SectionIngredientsSelected(ingredientAdded: addedIngre)
SectionIngredientsSelection(ingredients: ingredients)
}
}
}
You are creating two different instances of AddedIngredients. These do not synchronize their content with each other. The simpelest solution would be to pull the AddedIngredients up into CreationView and pass it down to the sub views.
So change your CreationView to:
struct CreationView: View {
let ingredients: [Ingredient] = Bundle.main.decode("Ingredients.json")
#StateObject private var addedIngre: AddedIngredients = AddedIngredients()
and:
SectionIngredientsSelected(ingredientAdded: addedIngre)
SectionIngredientsSelection(ingredients: ingredients, ajoute: addedIngre)
and SectionIngredientsSelection to:
struct SectionIngredientsSelection: View {
let ingredients: [Ingredient]
#ObservedObject var ajoute: AddedIngredients
Remarks:
It is not perfectly clear for me how CreationView aquires addedIngre. From your code it seems it gets somehow injected. If this is the case and you need it upward the view hierachy, change the #StateObject to #ObservedObject. But make sure it is initialized with #StateObject.

SwiftUI - How to add a screen to a section of segmental control

I have coded a currency converter page, however I want to add this converter to a section on a segmented control. How can I add this page to one section in a segmented control so one section of the control is currency conversion and then when I click on the other section it will take me to another page?
import SwiftUI
struct ContentView: View {
#State var input = "100"
#State var base = "USD"
#State var currencyList = [String]()
#FocusState private var inputIsFocused: Bool
func makeRequest (showAll: Bool, currencies: [String] = ["USD", "GBP", "EUR"]) {
apiRequest(url:
"https:api.exchangerate.host/latest?base=\(base)&amount=\(input)") { currency in
var tempList = [String]()
for currency in currency.rates {
if showAll {
tempList.append("\(currency.key) \(String(format: "%.2f", currency.value))")
} else if currencies.contains(currency.key) {
tempList.append("\(currency.key) \(String(format: "%.2f", currency.value))")
}
tempList.sort()
}
currencyList.self = tempList
print(tempList)
}
}
var body: some View {
VStack {
HStack {
Text("Currencies")
.font(.system(size: 30))
.bold()
Image(systemName: "yensign.square")
.font(.system(size: 30))
.foregroundColor(.black)
}
List {
ForEach(currencyList, id: \.self) { currency in
Text(currency)
}
}
VStack {
Rectangle()
.frame(height: 8.0)
.foregroundColor(.black)
.opacity(0.90)
TextField("Enter an Amount", text: $input)
.padding()
.background(Color.gray.opacity(0.10))
.cornerRadius(20.0)
.padding()
.keyboardType(.decimalPad)
.focused($inputIsFocused)
TextField("Enter a Currency", text: $base)
.padding()
.background(Color.gray.opacity(0.10))
.cornerRadius(20.0)
.padding()
.focused($inputIsFocused)
Button("Convert") {
makeRequest(showAll: true, currencies: ["DKK", "SEK" ,"NOK"])
inputIsFocused = false
}.padding()
}
}.onAppear {
makeRequest(showAll: true)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View{
ContentView()
}
}
`
I built the segmented control separate to the converter, however one was built with SwiftUi and the other was built using storyboard, so How can I combine the two?

How could I correctly implement favourites in SwiftUI?

I am building an app that will store multiple Nintendo consoles and their details (kinda like Mactracker but for Nintendo stuff).
I wanna store consoles that the user chooses in a favourites category on the main menu but I can't implement it correctly.
I have the main menu which shows the different categories as well as the favourite category which is duplicated for each category:
Each favourites "button" takes me to the favourites of only a specific category (the category beneath it) and I would like that all of them are in only one tab and not in multiple tabs like they are so far.
The favourites category is a bool defined in the Console List which will be listed below.
Thanks for the help and sorry if its a stupid question, I'm quite new to programming.
Main Menu:
struct MainMenu: View {
// Use categories ordered by alphabetical order
var categories = ConsoleList.categories.sorted(by: {$0.key < $1.key})
var body: some View {
// Loop on categories
NavigationView{
List(categories, id:\.key){category in
// The NavigationLink that takes me to the favorites view
NavigationLink(destination: Favorites(con: category.value)){
Image(systemName: "heart")
Text("Favorites")
.fontWeight(.semibold)
}
NavigationLink(destination: ConsoleMenu(con: category.value), label:{
Image(systemName: "folder")
.foregroundColor(.red)
.scaledToFit()
.frame(height: 30)
.cornerRadius(4)
.padding(.vertical, 4)
VStack{
Text(category.key)
.fontWeight(.semibold)
}
})
}
.navigationTitle("")
}
}
}
Favourites menu:
struct Favorites: View {
var con: [ConsoleDetails]
var body: some View {
List(con){ cons in
if cons.favorites {
NavigationLink(destination: ConsoleDetailView(con: cons), label:{
Image(cons.imgName)
.resizable()
.scaledToFit()
.frame(height: 50)
.cornerRadius(4)
.padding(.vertical, 4)
.navigationTitle("\(cons.category)")
VStack (alignment: .leading){
if cons.category == "Game & Watch" {
Text(cons.consoleName)
.fontWeight(.semibold)
Text(cons.mostSoldGame)
.font(.subheadline)
}else{
Text(cons.consoleName)
.fontWeight(.semibold)
}
}
}).navigationTitle("Favorites")
}
}
}
}
struct favorites_Previews: PreviewProvider {
static var previews: some View {
Favorites(con: ConsoleList.consoles)
}
}
The consoles list:
struct ConsoleDetails: Identifiable{
let id = UUID()
var imgName: String = ""
var consoleName: String = ""
var mostSoldGame: String = ""
var initialPrice: String = ""
var ReleaseDate: String = ""
var Discontinuation: String = ""
var category: String = ""
var estimatedPricedToday: String = ""
var cables: String = ""
var favorites: Bool
}
struct ConsoleList{
//The consoles list has more consoles usually but I'll only put one to save space
static var categories = Dictionary(grouping: consoles, by: {$0.category } )
static var favs = Dictionary(grouping: consoles, by: {$0.favorites} )
static var consoles = [
//Current Consoles
ConsoleDetails(imgName: "NS_OG",
consoleName: "Nintendo Switch",
mostSoldGame: "Mario Kart 8 Deluxe",
initialPrice: "299.99",
ReleaseDate: "Mar 3, 2017",
Discontinuation: "Still Available",
category: "Current Consoles",
estimatedPricedToday: "$200-250 used",
cables: "HDMI, USB Type-C",
favorites: true),
Edit: I have added what was proposed but I get an error in the nav link. See below:
List{
Section {
// The NavigationLink that takes me to the favorites view
NavigationLink {
Favorites() // Right Here: Missing argument for parameter 'con' in call
} label: {
Image(systemName: "heart")
Text("Favorites")
.fontWeight(.semibold)
}
}
Section {
ForEach(categories, id: \.key){ category in
NavigationLink(destination: ConsoleMenu(con: category.value), label:{
Image(systemName: "folder")
.foregroundColor(.red)
.scaledToFit()
.frame(height: 30)
.cornerRadius(4)
.padding(.vertical, 4)
VStack{
Text(category.key)
.fontWeight(.semibold)
}
})
}
}
}
Instead of having the list loop over the categories, you could put a ForEach in the List.
Then, you could have one favorites link, and put it in a different section to differentiate it.
List {
Section {
NavigationLink {
Favorites(con: /* (1) */ ConsoleList.consoles)
} label: { /* ... */ }
}
Section {
ForEach(categories, id: \.key) { category in
// ...
}
}
}
(1) You will also need to pass in a list of all the consoles to show.

Getting Values from own PickerView

I'm new to Swift and I'm currently developing my own Timer Application for practice purposes. (I do it without storyboard)
Now I have the Problem that i made a View called "TimePickerView" (Code below), where I created my own Picker. Then I use that TimePickerView in another part of my Application with other Views (in a View). In that View I want to pick my time but I don't know how i can get the Values of the Picker (The Picker works by the way)
This is my TimePickerView
import SwiftUI
struct TimePickerView: View {
#State private var selectedTimeIndexSecond = 0
#State private var selectedTimeIndexMinutes = 0
#State private var seconds : [Int] = Array(0...59)
#State private var minutes : [Int] = Array(0...59)
var body: some View {
VStack{
Text("Select Your Time")
HStack{
//minutes-Picker
Picker("select time", selection: $selectedTimeIndexMinutes, content: {
ForEach(0..<minutes.count, content: {
index in
Text("\(minutes[index]) min").tag(index)
})
})
.padding()
.frame(width: 120)
.clipped()
//seconds-Picker
Picker("select time", selection: $selectedTimeIndexSecond, content: {
ForEach(0..<seconds.count, content: {
index in
Text("\(seconds[index]) sec").tag(index)
})
})
.padding()
.frame(width: 120)
.clipped()
Spacer()
}
Text("You picked the time")
.multilineTextAlignment(.center)
.font(.title2)
.padding()
Text("\(minutes[selectedTimeIndexMinutes]) min : \(seconds[selectedTimeIndexSecond]) sec")
.font(.title)
.bold()
.padding(.top, -14.0)
}
}
func getValues() -> (Int, Int) {
return (self.minutes[selectedTimeIndexMinutes] ,self.seconds[selectedTimeIndexSecond])
}
}
and that is the View I want to use my Picker, but I don't know how I get those values from the Picker:
struct SetTimerView: View {
#State var timepicker = TimePickerView()
var body: some View {
NavigationView{
VStack{
//Select the time
timepicker
//Timer variables (This doesn't work)
var timerTime = timepicker.getValues()
var minutes = timerTime.0
var seconds = timerTime.1
Spacer()
let valid : Bool = isValid(timerTime: minutes+seconds)
//Confirm the time
NavigationLink(
destination:
getRightView(
validBool: valid,
timerTime: minutes*60 + seconds),
label: {
ConfirmButtonView(buttonText: "Confirm")
});
Spacer()
}
}
}
func isValid(timerTime : Int) -> Bool {
if (timerTime == 0) {
return false
} else {
return true
}
}
#ViewBuilder func getRightView(validBool : Bool, timerTime : Int) -> some View{
if (validBool == true) {
TimerView(userTime: CGFloat(timerTime), name: "David", isActive: true)
} else {
UnvalidTimeView()
}
}
}
I think main problem is misunderstanding conceptions between data and views.
At first you need a model witch will override your data (create it in separate swift file):
import Foundation
class Time: ObservableObject {
#Published var selectedTimeIndexMinutes: Int = 0
#Published var selectedTimeIndexSecond: Int = 0
}
Pay attention on ObservableObject so that swiftUI can easily detect changes to it that trigger any active views to redraw.
Next I try to change the value of the model in the view
import SwiftUI
struct TimePickerView: View {
#EnvironmentObject var timeData: Time
#State private var seconds : [Int] = Array(0...59)
#State private var minutes : [Int] = Array(0...59)
var body: some View {
VStack{
Text("Select Your Time")
HStack{
//minutes-Picker
Picker("select time", selection: $timeData.selectedTimeIndexMinutes, content: {
ForEach(0..<minutes.count, content: {
index in
Text("\(minutes[index]) min").tag(index)
})
})
.padding()
.frame(width: 120)
.clipped()
//seconds-Picker
Picker("select time", selection: $timeData.selectedTimeIndexSecond, content: {
ForEach(0..<seconds.count, content: {
index in
Text("\(seconds[index]) sec").tag(index)
})
})
.padding()
.frame(width: 120)
.clipped()
Spacer()
}
Text("You picked the time")
.multilineTextAlignment(.center)
.font(.title2)
.padding()
Text("\(timeData.selectedTimeIndexMinutes) min : \(timeData.selectedTimeIndexSecond) sec")
.font(.title)
.bold()
.padding(.top, -14.0)
}
}
}
struct TimePickerView_Previews: PreviewProvider {
static var previews: some View {
TimePickerView()
.environmentObject(Time())
}
}
Like you can see I don't using #Blinding, instead of it I connecting our Model with a View
On the next view I can see changes, I created a new one because your example have view that don't indicated here...
import SwiftUI
struct ReuseDataFromPicker: View {
#EnvironmentObject var timeData: Time
var body: some View {
VStack{
Text("You selected")
Text("\(timeData.selectedTimeIndexMinutes) min and \(timeData.selectedTimeIndexSecond) sec")
}
}
}
struct ReuseDataFromPicker_Previews: PreviewProvider {
static var previews: some View {
ReuseDataFromPicker()
.environmentObject(Time())
}
}
And collect all in a Content View
struct ContentView: View {
var body: some View {
TabView {
TimePickerView()
.tabItem {Label("Set Timer", systemImage: "clock.arrow.2.circlepath")}
ReuseDataFromPicker()
.tabItem {Label("Show Timer", systemImage: "hourglass")}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(Time())
}
}
Like that you can easily change or reuse your data on any other views

Swiftui navigationLink macOS default/selected state

I build a macOS app in swiftui
i try to create a listview where the first item is preselected. i tried it with the 'selected' state of the navigationLink but it didn't work.
Im pretty much clueless and hope you guys can help me.
The code for creating this list view looks like this.
//personList
struct PersonList: View {
var body: some View {
NavigationView
{
List(personData) { person in
NavigationLink(destination: PersonDetail(person: person))
{
PersonRow(person: person)
}
}.frame(minWidth: 300, maxWidth: 300)
}
}
}
(Other views at the bottom)
This is the normal View when i open the app.
When i click on an item its open like this. Thats the state i want as default opening state when i render this view.
The Code for this view looks like this:
//PersonRow
struct PersonRow: View {
//variables definied
var person: Person
var body: some View {
HStack
{
person.image.resizable().frame(width:50, height:50)
.cornerRadius(25)
.padding(5)
VStack (alignment: .leading)
{
Text(person.firstName + " " + person.lastName)
.fontWeight(.bold)
.padding(5)
Text(person.nickname)
.padding(5)
}
Spacer()
}
}
}
//personDetail
struct PersonDetail: View {
var person : Person
var body: some View {
VStack
{
HStack
{
VStack
{
CircleImage(image: person.image)
Text(person.firstName + " " + person.lastName)
.font(.title)
Text("Turtle Rock")
.font(.subheadline)
}
Spacer()
Text("Subtitle")
.font(.subheadline)
}
Spacer()
}
.padding()
}
}
Thanks in advance!
working example. See how selection is initialized
import SwiftUI
struct Detail: View {
let i: Int
var body: some View {
Text("\(self.i)").font(.system(size: 150)).frame(maxWidth: .infinity)
}
}
struct ContentView: View {
#State var selection: Int?
var body: some View {
HStack(alignment: .top) {
NavigationView {
List {
ForEach(0 ..< 10) { (i) in
NavigationLink(destination: Detail(i: i), tag: i, selection: self.$selection) {
VStack {
Text("Row \(i)")
Divider()
}
}
}.onAppear {
if self.selection != nil {
self.selection = 0
}
}
}.frame(width: 100)
}
}.background(Color.init(NSColor.controlBackgroundColor))
}
}
screenshot
You can define a binding to the selected row and used a List reading this selection. You then initialise the selection to the first person in your person array.
Note that on macOS you do not use NavigationLink, instead you conditionally show the detail view with an if statement inside your NavigationView.
If person is not Identifiable you should add an id: \.self in the loop. This ressembles to:
struct PersonList: View {
#Binding var selectedPerson: Person?
var body: some View {
List(persons, id: \.self, selection: $selectedPerson) { person in // persons is an array of persons
PersonRow(person: person).tag(person)
}
}
}
Then in your main window:
struct ContentView: View {
// First cell will be highlighted and selected
#State private var selectedPerson: Person? = person[0]
var body: some View {
NavigationView {
PersonList(selectedPerson: $selectedPerson)
if selectedPerson != nil {
PersonDetail(person: person!)
}
}
}
}
Your struct person should be Hashable in order to be tagged in the list. If your type is simple enough, adding Hashable conformance should be sufficient:
struct Person: Hashable {
var name: String
// ...
}
There is a nice tutorial using the same principle here if you want a more complete example.
Thanks to this discussion, as a MacOS Beginner, I managed a very basic NavigationView with a list containing two NavigationLinks to choose between two views. I made it very basic to better understand. It might help other beginners.
At start up it will be the first view that will be displayed.
Just modify in ContentView.swift, self.selection = 0 by self.selection = 1 to start with the second view.
FirstView.swift
import SwiftUI
struct FirstView: View {
var body: some View {
Text("(1) Hello, I am the first view")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct FirstView_Previews: PreviewProvider {
static var previews: some View {
FirstView()
}
}
SecondView.swift
import SwiftUI
struct SecondView: View {
var body: some View {
Text("(2) Hello, I am the second View")
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct SecondView_Previews: PreviewProvider {
static var previews: some View {
SecondView()
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
#State var selection: Int?
var body: some View {
HStack() {
NavigationView {
List () {
NavigationLink(destination: FirstView(), tag: 0, selection: self.$selection) {
Text("Click Me To Display The First View")
} // End Navigation Link
NavigationLink(destination: SecondView(), tag: 1, selection: self.$selection) {
Text("Click Me To Display The Second View")
} // End Navigation Link
} // End list
.frame(minWidth: 350, maxWidth: 350)
.onAppear {
self.selection = 0
}
} // End NavigationView
.listStyle(SidebarListStyle())
.frame(maxWidth: .infinity, maxHeight: .infinity)
} // End HStack
} // End some View
} // End ContentView
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Result:
import SwiftUI
struct User: Identifiable {
let id: Int
let name: String
}
struct ContentView: View {
#State private var users: [User] = (1...10).map { User(id: $0, name: "user \($0)")}
#State private var selection: User.ID?
var body: some View {
NavigationView {
List(users) { user in
NavigationLink(tag: user.id, selection: $selection) {
Text("\(user.name)'s DetailView")
} label: {
Text(user.name)
}
}
Text("Select one")
}
.onAppear {
if let selection = users.first?.ID {
self.selection = selection
}
}
}
}
You can use make the default selection using onAppear (see above).