Search code examples
swiftswiftuisplitview

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. appnormalstate When i click on an item its open like this. Thats the state i want as default opening state when i render this view. appwantedstate

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!


Solution

  • 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.