I am using swiftui to update an app which can display a detail screen based on the users picker selection. I created a view for each detail screen(about 50) and I have a multi-picker for the user to select which detail screen to display. What is the best way to use the selections from the picker to show the appropriate detail view.
Here is an simplified example of the multi-picker:
struct PickerMenu: View {
enum HypoHyper: String, CaseIterable, Identifiable {
case Hypo
case Hyper
var id: String { self.rawValue }
}
enum Lytes: String, CaseIterable, Identifiable {
case Na
case K
var id: String { self.rawValue }
}
enum Details: String, CaseIterable, Identifiable {
case Causes
case Signs
var id: String { self.rawValue }
}
#State var selectedHypoHyper = HypoHyper.Hyper
#State var selectedLyte = Lytes.Na
#State var selectedDetail = Details.Causes
var body: some View {
GeometryReader { geometry in
HStack {
Picker(selection: self.$selectedHypoHyper, label: Text("")) {
ForEach(HypoHyper.allCases) { hypoHyper in
Text(hypoHyper.rawValue).tag(hypoHyper.rawValue)
}
}
.frame(width: geometry.size.width/3, height: 150, alignment: .center)
.clipped( )
Picker(selection: self.$selectedLyte, label: Text("")) {
ForEach(Lytes.allCases) { lyte in
Text(lyte.rawValue).tag(lyte.rawValue)
}
}
.frame(width: geometry.size.width/3, height: 150, alignment: .center)
.clipped( )
Picker(selection: self.$selectedDetail, label: Text("")) {
ForEach(Details.allCases) { detail in
Text(detail.rawValue).tag(detail.rawValue)
}
}
.frame(width: geometry.size.width/3, height: 150, alignment: .center)
.clipped( )
}
}
}
}
there various ways to do this, here is a simple approach:
(note I had to modify the Pickers)
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
PickerMenu()
}.navigationViewStyle(StackNavigationViewStyle())
}
}
// put these outside the PickerMenu for other views to use
enum HypoHyper: String, CaseIterable, Identifiable {
case Hypo
case Hyper
var id: String { self.rawValue }
}
enum Lytes: String, CaseIterable, Identifiable {
case Na
case K
var id: String { self.rawValue }
}
enum Details: String, CaseIterable, Identifiable {
case Causes
case Signs
var id: String { self.rawValue }
}
struct PickerMenu: View {
#State var selectedHypoHyper: HypoHyper = HypoHyper.Hyper
#State var selectedLyte = Lytes.Na
#State var selectedDetail = Details.Causes
#State var showDetailView = false
var body: some View {
VStack (spacing: 30) {
GeometryReader { geometry in
HStack {
Picker("", selection: $selectedHypoHyper) {
ForEach(HypoHyper.allCases, id: \.id) { hypoHyper in
Text(hypoHyper.rawValue).tag(hypoHyper)
}
}
.frame(width: geometry.size.width/3, height: 150, alignment: .center)
.clipped( )
Picker("", selection: $selectedLyte) {
ForEach(Lytes.allCases, id: \.id) { lyte in
Text(lyte.rawValue).tag(lyte)
}
}
.frame(width: geometry.size.width/3, height: 150, alignment: .center)
.clipped( )
Picker("", selection: $selectedDetail) {
ForEach(Details.allCases, id: \.id) { detail in
Text(detail.rawValue).tag(detail)
}
}
.frame(width: geometry.size.width/3, height: 150, alignment: .center)
.clipped( )
}
}
Button("Show Detail View") {
showDetailView = true
}
NavigationLink("", destination: SomeDetailView(
selectedHypoHyper: $selectedHypoHyper,
selectedLyte: $selectedLyte,
selectedDetail: $selectedDetail), isActive: $showDetailView)
}
}
}
struct SomeDetailView: View {
#Binding var selectedHypoHyper: HypoHyper
#Binding var selectedLyte: Lytes
#Binding var selectedDetail: Details
var body: some View {
// here determine which view you want to show based on the selections, eg a switch(...) {..}
Text("selectedHypoHyper: \(selectedHypoHyper.rawValue)")
Text("selectedLyte: \(selectedLyte.rawValue)")
Text("selectedDetail: \(selectedDetail.rawValue)")
}
}
Does this one helps, here we are using a switch statement and return a view (or a NavigationLink) depending on the context
switch (selectedHypoHyper, selectedLyte, selectedDetail) {
case (.Hyper, .Na, .Causes): EmptyView()
case (.Hyper, .Na, .Signs): EmptyView()
case (.Hyper, .K, .Causes): EmptyView()
case (.Hyper, .K, .Signs): EmptyView()
// Continue with other cases ...
default: EmptyView()
}
Related
Having difficulties with my tabView, (which has been custom made to accommodate my gridView which allows picture buttons taking me to a new display). Displaying a blank View with "back" button on launch. Then after selecting tab 2 and coming back to tab 1, displays the screen in full detail. After some testing the navigationlink is the cause but i'm confused on the resolution.
Within my main build the navigationTitle sits mid centre the screen and when scrolled greys out a large sections. I believe this is due to there being multiple navigationlinks/views creating a rectangle block where the navigationlView/Links are sitting on top of each other.
TabView
struct headerView: View {
#State var currentTab: Int = 0
var body: some View {
VStack {
TabBarView(currentTab: self.$currentTab)
.padding(10)
TabView(selection: self.$currentTab) {
grid().tag(0)
tabView2().tag(1)
tabView3().tag(2)
}
.tabViewStyle(.page(indexDisplayMode: .never))
.edgesIgnoringSafeArea(.all)
}
}
}
struct TabBarView: View {
#Binding var currentTab: Int
#Namespace var namespace
var tabBarOptions: [String] = ["Test 1", "Test 2", "Test 3"]
var body: some View {
HStack {
ForEach(Array(zip(self.tabBarOptions.indices,
self.tabBarOptions)),
id: \.0,
content: {
index, name in
TabBarItem(currentTab: self.$currentTab,
namespace: namespace.self,
tabBarItemName: name,
tab: index)
})
}
.frame(width: (UIScreen.main.bounds.width / 1.25) - 1)
.background(Color.white)
.frame(height: 50)
}
}
struct TabBarItem: View {
#Binding var currentTab: Int
let namespace: Namespace.ID
var tabBarItemName: String
var tab: Int
var body: some View {
Button {
self.currentTab = tab
} label: {
VStack {
Spacer()
Text(tabBarItemName)
if currentTab == tab {
Color.black
.frame(height: 2)
.matchedGeometryEffect(id: "underline",
in: namespace,
properties: .frame)
} else {
Color.clear.frame(height: 2)
}
}
.animation(.spring(), value: self.currentTab)
}
.buttonStyle(.plain)
}
}
TabView2
struct tabView2: View {
var body: some View {
VStack {
Text("Hello")
}
}
}
imageGrid
enum ImageEnum: String, CaseIterable { //Please find a better name ;)
case image1, image2
var imageName: String { // get the assetname of the image
switch self {
case .image1:
return "image1"
case .image2:
return "image2"
}
}
#ViewBuilder
var detailView: some View { // create the view here, if you need to add
switch self { // parameters use a function or associated
case .image1: // values for your enum cases
TestView1()
case .image2:
TestView2()
}
}
}
struct grid: View {
var columnGrid: [GridItem] = [GridItem(.flexible(), spacing: 25), GridItem(.flexible(), spacing: 25)]
var body: some View {
NavigationView{ // Add the NavigationView
LazyVGrid(columns: columnGrid, spacing: 50) {
ForEach(ImageEnum.allCases, id:\.self) { imageEnum in // Iterate over all enum cases
NavigationLink(destination: imageEnum.detailView){ // get detailview here
Image(imageEnum.imageName) // get image assset name here
.resizable()
.scaledToFill()
.clipped()
.cornerRadius(25)
}
}
}
}
}
}
TestView
struct TestView1: View{
var body: some View{
Text("test1")
}
}
struct TestView2: View{
var body: some View{
Text("test2")
}
}
I am trying to append to a struct from another file. I can do so, and it works in one file, but when I try to connect the second, it doesn't work.
I am trying to implement a checkout feature, and right now, I need to at least be able to append items to the cart.
currentOrderLogic.swift
struct Cart: Hashable, Identifiable {
let id = UUID()
var product_name: String
var product_cost: String
}
public struct CurrentOrder: View {
#State var items = [Cart]()
func addObject(product_name: String, product_cost: String) {
items.append(Cart(product_name: product_name, product_cost: product_cost))
}
public var body: some View {
ScrollView(.vertical) {
VStack(alignment: .center) {
Text("Current Order".uppercased()).font(.system(size: 30))
.frame(height:50)
ForEach(items, id: \.self) { item in
HStack{
Text(item.product_name)
Text(item.product_cost)
}
}
Spacer()
Button("Charge $0.00") {
addObject(product_name: "Aooke", product_cost: "6")
}
}
}
}
}
When I press the button, it is added and shown in the list.
Now, I am trying to have items that they can click, and when it is clicked, the item is added to the current order.
homeMenu.swift
struct homeMenuObject: View {
#State var posts: [Post] = []
let date = Date()
var body: some View {
VStack {
HStack {
Text(date, style: .date)
Text(date, style: .time)
}
WrappingHStack(posts, id: \.self){ item in
VStack {
HStack {
Image("Logo").resizable().frame(width: 110, height: 55)
}
HStack {
Text(item.title)
}
HStack {
Text((item.body).uppercased())
.font(.headline)
}
}.frame(width: 110, height: 140).background(Color.white).onTapGesture {
CurrentOrder().addObject(product_name: "Aooke", product_cost: "6")
}
}.onAppear {
Api().getPosts { (posts) in
self.posts = posts
}
}
Spacer()
}
}
}
But when CurrentOrder().addObject(product_name: "Aooke", product_cost: "6") is called, nothing happens. How can I fix this?
Using ObservedObjects, I figured this out MYSELF.
currentOrderLogic.swift
public struct CurrentOrder: View {
#ObservedObject var cartSystem : CartSystem
public var body: some View {
ScrollView(.vertical) {
VStack(alignment: .center) {
Text("Current Order".uppercased()).font(.system(size: 30))
.frame(height:50)
ForEach(cartSystem.items, id: \.self) { item in
HStack{
Text(item.product_name)
Text(item.product_cost)
}
}
Spacer()
Button("Charge $0.00") {
cartSystem.addObject(product_name: "Aooke", product_cost: "6")
}
}
}
}
}
homeMenu.swift
struct homeMenuObject: View {
#State var posts: [Post] = []
#ObservedObject var cartSystem : CartSystem
let date = Date()
var body: some View {
VStack {
HStack {
Text(date, style: .date)
Text(date, style: .time)
}
WrappingHStack(posts, id: \.self){ item in
VStack {
HStack {
Image("Logo").resizable().frame(width: 110, height: 55)
}
HStack {
Text(item.title)
}
HStack {
Text((item.body).uppercased())
.font(.headline)
}
}.frame(width: 110, height: 140).background(Color.white).onTapGesture {
cartSystem.addObject(product_name: "Aooke", product_cost: "6")
}
}.onAppear {
Api().getPosts { (posts) in
self.posts = posts
}
}
Spacer()
}
}
}
Then, in your main ContentView, I put this outside of the ContentView Structure,
class CartSystem: ObservableObject {
#Published var items = [Cart]()
func addObject(product_name: String, product_cost: String) {
self.items.append(Cart(product_name: product_name, product_cost: product_cost))
}
struct Cart: Hashable, Identifiable {
let id = UUID()
var product_name: String
var product_cost: String
}
}
Then I put this inside the ContentView struct
#StateObject var cartSystem : CartSystem = CartSystem()
Then, when I call the CurrentOrder struct and the HomeMenu struct, you pass this cartSystem variable in. This makes all of the CartSystem's the same, so you are not creating new instances of them and makes them connected.
Now i need to make the homeMenu objects pass their respective data into the order
I want when I finish selecting the language and click the Save button it will return the ContentView page and display the language I have selected. And when I click again, it has to checkmark the language I selected before.
I have successfully displayed the data, but I don't know how to save it when I click the Save button
Here is all my code currently
ContentView
struct ContentView: View {
var body: some View {
NavigationView {
HStack {
NavigationLink(destination:LanguageView() ) {
Text("Language")
Spacer()
Text("I want to show the language here ")
}
}
}
}
}
LanguageView
struct LanguageView: View {
var body: some View {
VStack {
CustomLanguageView()
Button(action: {
})
{
Text("Save")
.foregroundColor(.black)
}
.padding()
Spacer()
}
}
}
struct CustomLanguageView: View {
var language = ["US", "English", "Mexico", "Canada"]
#State var selectedLanguage: String? = nil
var body: some View {
LazyVStack {
ForEach(language, id: \.self) { item in
SelectionCell(language: item, selectedLanguage: self.$selectedLanguage)
.padding(.trailing,40)
Rectangle().fill(Color.gray)
.frame( height: 1,alignment: .bottom)
}
.frame(height:15)
}
}
}
struct SelectionCell: View {
let language: String
#Binding var selectedLanguage: String?
var body: some View {
HStack {
Text(language)
Spacer()
if language == selectedLanguage {
Image(systemName: "checkmark")
.resizable()
.frame(width:20, height: 15)
}
}
.onTapGesture {
self.selectedLanguage = self.language
}
}
}
There are multiple ways to "Save" something but if you are just trying to get it back to the other view you could do something like this that I quickly setup.
struct ContentView: View {
#State var language: String? = ""
var body: some View {
NavigationView {
HStack {
NavigationLink(destination:LanguageView(language: $language)) {
Text("Language")
.padding()
Spacer()
Text(language!)
.padding()
}
}
}
}
}
struct LanguageView: View {
#Binding var language: String?
#State var selectedLanguage: String? = ""
var body: some View {
VStack {
CustomLanguageView(selectedLanguage: $selectedLanguage)
Button(action: {
language = selectedLanguage
})
{
Text("Save")
.foregroundColor(.black)
}
.padding()
Spacer()
}
}
}
struct CustomLanguageView: View {
var language = ["US", "English", "Mexico", "Canada"]
#Binding var selectedLanguage: String?
var body: some View {
LazyVStack {
ForEach(language, id: \.self) { item in
SelectionCell(language: item, selectedLanguage: self.$selectedLanguage)
.padding(.trailing,40)
Rectangle().fill(Color.gray)
.frame( height: 1,alignment: .bottom)
}
.frame(height:15)
}
}
}
struct SelectionCell: View {
let language: String
#Binding var selectedLanguage: String?
var body: some View {
HStack {
Text(language)
Spacer()
if language == selectedLanguage {
Image(systemName: "checkmark")
.resizable()
.frame(width:20, height: 15)
}
}
.onTapGesture {
self.selectedLanguage = self.language
}
}
}
Or if you are actually trying to save it to the device for later use you could use
UserDefaults.standard.setValue(selectedLanguage, forKey: "language")
Then to Retrieve it later do
UserDefaults.standard.value(forKey: "language") as! String
I am attempting to build a multifaceted openweathermap app. My app is designed to prompt the user to input a city name on a WelcomeView, in order to get weather data for that city. After clicking search, the user is redirected to a sheet with destination: DetailView, which displays weather details about that requested city. My goal is to disable dismissal of the sheet in WelcomeView and instead add a navigationlink to the sheet that redirects to the ContentView. The ContentView in turn is set up to display a list of the user's recent searches (also in the form of navigation links).
My issues are the following:
The navigationLink in the WelcomeView sheet does not work. It appears to be disabled. How can I configure the navigationLink to segue to destination: ContentView() ?
After clicking the navigationLink and redirecting to ContentView, I want to ensure that the city name entered in the WelcomeView textfield is rendered as a list item in the ContentView. For that to work, would it be necessary to set up an action in NavigationLink to call viewModel.fetchWeather(for: cityName)?
Here is my code:
WelcomeView
struct WelcomeView: View {
#StateObject var viewModel = WeatherViewModel()
#State private var cityName = ""
#State private var showingDetail: Bool = false
#State private var linkActive: Bool = true
#State private var acceptedTerms = false
var body: some View {
Section {
HStack {
TextField("Search Weather by City", text: $cityName)
.padding()
.overlay(RoundedRectangle(cornerRadius: 10.0).strokeBorder(Color.gray, style: StrokeStyle(lineWidth: 1.0)))
.padding()
Spacer()
Button(action: {
viewModel.fetchWeather(for: cityName)
cityName = ""
self.showingDetail.toggle()
}) {
HStack {
Image(systemName: "plus")
.font(.title)
}
.padding(15)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(40)
}
.sheet(isPresented: $showingDetail) {
VStack {
NavigationLink(destination: ContentView()){
Text("Return to Search")
}
ForEach(0..<viewModel.cityNameList.count, id: \.self) { city in
if (city == viewModel.cityNameList.count-1) {
DetailView(detail: viewModel.cityNameList[city])
}
}.interactiveDismissDisabled(!acceptedTerms)
}
}
}.padding()
}
}
}
struct WelcomeView_Previews: PreviewProvider {
static var previews: some View {
WelcomeView()
}
}
ContentView
let coloredToolbarAppearance = UIToolbarAppearance()
struct ContentView: View {
// Whenever something in the viewmodel changes, the content view will know to update the UI related elements
#StateObject var viewModel = WeatherViewModel()
#State private var cityName = ""
#State var showingDetail = false
init() {
// toolbar attributes
coloredToolbarAppearance.configureWithOpaqueBackground()
coloredToolbarAppearance.backgroundColor = .systemGray5
UIToolbar.appearance().standardAppearance = coloredToolbarAppearance
UIToolbar.appearance().scrollEdgeAppearance = coloredToolbarAppearance
}
var body: some View {
NavigationView {
VStack() {
List () {
ForEach(viewModel.cityNameList) { city in
NavigationLink(destination: DetailView(detail: city)) {
HStack {
Text(city.name).font(.system(size: 32))
Spacer()
Text("\(city.main.temp, specifier: "%.0f")°").font(.system(size: 32))
}
}
}.onDelete { index in
self.viewModel.cityNameList.remove(atOffsets: index)
}
}.onAppear() {
viewModel.fetchWeather(for: cityName)
}
}.navigationTitle("Weather")
.toolbar {
ToolbarItem(placement: .bottomBar) {
HStack {
TextField("Enter City Name", text: $cityName)
.frame(minWidth: 100, idealWidth: 150, maxWidth: 240, minHeight: 30, idealHeight: 40, maxHeight: 50, alignment: .leading)
Spacer()
Button(action: {
viewModel.fetchWeather(for: cityName)
cityName = ""
self.showingDetail.toggle()
}) {
HStack {
Image(systemName: "plus")
.font(.title)
}
.padding(15)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(40)
}.sheet(isPresented: $showingDetail) {
ForEach(0..<viewModel.cityNameList.count, id: \.self) { city in
if (city == viewModel.cityNameList.count-1) {
DetailView(detail: viewModel.cityNameList[city])
}
}
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
DetailView
struct DetailView: View {
var detail: WeatherModel
var body: some View {
VStack(spacing: 20) {
Text(detail.name)
.font(.system(size: 32))
Text("\(detail.main.temp, specifier: "%.0f")°")
.font(.system(size: 44))
Text(detail.firstWeatherInfo())
.font(.system(size: 24))
}
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
DetailView(detail: WeatherModel.init())
}
}
ViewModel
class WeatherViewModel: ObservableObject {
#Published var cityNameList = [WeatherModel]()
func fetchWeather(for cityName: String) {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&units=imperial&appid=<MyAPIKey>") else { return }
let task = URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data, error == nil else { return }
do {
let model = try JSONDecoder().decode(WeatherModel.self, from: data)
DispatchQueue.main.async {
self.cityNameList.append(model)
}
}
catch {
print(error) // <-- you HAVE TO deal with errors here
}
}
task.resume()
}
}
Model
struct WeatherModel: Identifiable, Codable {
let id = UUID()
var name: String = ""
var main: CurrentWeather = CurrentWeather()
var weather: [WeatherInfo] = []
func firstWeatherInfo() -> String {
return weather.count > 0 ? weather[0].description : ""
}
}
struct CurrentWeather: Codable {
var temp: Double = 0.0
}
struct WeatherInfo: Codable {
var description: String = ""
}
DemoApp
#main
struct SwftUIMVVMWeatherDemoApp: App {
var body: some Scene {
WindowGroup {
// ContentView()
WelcomeView()
}
}
}
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).