SwiftUI NavigationLink 的 macOS 默认和选中状态

17

我使用SwiftUI构建了一个macOS应用程序

我尝试创建一个ListView,其中第一项被预先选择。我尝试使用navigationLink的“selected”状态,但它没有起作用。

我很茫然,希望你们能帮助我。

创建此列表视图的代码如下:

//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)
          }
    }
}

(其他视图在底部)

这是我打开应用程序时的普通视图。 appnormalstate 当我点击一个项目时,它会打开如下所示。这就是我希望在呈现此视图时作为默认打开状态的状态。 appwantedstate

该视图的代码如下:

//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()
    }
}

提前致谢!

4个回答

14

工作示例。查看如何初始化选择

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))
    }
}

屏幕截图 输入图片描述


1
嘿,谢谢你的回答,但是row0在开始时没有被突出显示... - lvollmer
优秀的回答。要默认高亮显示行,请将“List”修改为“List(selection:self.$selection)”。 - Bijoy Thangaraj
我认为列表选择绑定参数仅用于编辑模式。 - malhal
它在iPad的竖屏模式(纵向模式)下不起作用。 - Alexander Volkov

12

您可以定义一个绑定到所选行的变量,并使用列表读取此选择。然后,将该选择初始化为您的人员数组中的第一个人。

请注意,在 macOS 上,您不使用 NavigationLink,而是在您的 NavigationView 中使用 if 语句有条件地显示详细视图。

如果“person”没有可识别性,则应在循环中添加 id: \.self。这类似于:

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)
    }
  }
}

然后在你的主窗口:

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!)
      }
    }
  }
}

如果您的结构体person需要被加入到列表中,请确保它实现了Hashable协议。如果您的类型足够简单,那么添加Hashable的一致性应该就足够了:

struct Person: Hashable {
  var name: String
  // ...
}

如果你想要一个更完整的例子,这里有一个使用相同原则的不错的教程


1
嘿,谢谢。我尝试了这样做,但它没有起作用...有没有调试功能之类的东西。我对SwiftUI还很陌生,抱歉...这是我的代码 https://pastebin.com/xcSRMb1x - lvollmer
1
不要在 macOS 上使用 NavigationLink,我会在我的答案中详细说明如何正确地做这件事。 - Louis Lac
这是一个晦涩的错误,我忘记提到两件事:Person 应该是可哈希的和可识别的。我在我的答案中添加了细节。 - Louis Lac
1
让我们在聊天中继续这个讨论 - Louis Lac
1
错误很明显:person变量不存在,变量名称是selectedPerson - Louis Lac
显示剩余7条评论

6

感谢这个讨论,作为一名MacOS初学者,我成功地使用一个包含两个NavigationLinks的列表实现了非常基本的NavigationView。我将其制作得非常基础以更好地理解。它可能会帮助其他初学者。

启动时将显示第一个视图。

只需在ContentView.swift中修改self.selection = 0为self.selection = 1即可从第二个视图开始。

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()
  }
}

结果:

输入图像描述


3
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
            }
        }
    }
}

您可以使用 onAppear(如上所述)来进行默认选择。


(^机器人的回复已经过时/真的没有帮助-答案已被编辑) - aehlke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接