如何在 Swiftui 导航旁边添加按钮 link

How to add buttons next to a Swiftui navigation link

我正在制作一个简单的清单应用程序,可让您查看有关项目的更多详细信息。我希望能够点击复选框(圆圈按钮)以删除项目或单击导航的其余部分 link 以进入该单独的页面。这是我在导航视图中嵌入列表的代码:

List {
  ForEach(fruitIds, id: \.self) { fruitId in
    HStack {
      Button {
        fruitIds.removeLast()
        fruits.remove(at: fruitId)
      } label: {
        Image(systemName: "circle")
          .imageScale(.large)
          .foregroundColor(.accentColor)
      }
      NavigationLink(destination: Text(fruits[fruitId])) {
        Text(fruits[fruitId])
      }
    }
  }
} 

目前,按下按钮或导航 link 会将您转到另一个屏幕,删除项目,然后将您送回列表。

顺便说一句,我声明了这两个数组

@State var fruits: [String] = ["apple", "orange", "banana", "peach"]
@State var fruitIds: [Int] = [0, 1, 2, 3]

此外,我对 Swift 还很陌生,绝对有更好的方法来完成此列表。

我正在从 那里回答你的按钮问题,所以请在此处注明。也可以在 .background() 中使用带有编程触发的 NavigationLinkButton 作为 NavigationLink。让它看起来像股票可能很棘手,这个解决方案可以满足你的要求。这个 不过,你也问了list的问题,这个问题很重要,理解一下。

首先,如果可能的话,避免在 ListForEach 等中使用 id: \.self。原因是它非常脆弱,会回来咬你当您尝试删除或移动项目时,或者列表中有两个“相同”项目时。你真的应该为此使用可识别的结构。对于这个答案,我使用:

struct Fruit: Identifiable {
    let id = UUID()
    var type: String
    // var color: Color, etc.
}

然后视图变成:

struct FruitListView: View {
    
    //  This array can have duplicate fruits and the ForEach is unaffected as the id's are different.
    @State var fruits: [Fruit] = [Fruit(type: "apple"),
                                  Fruit(type: "orange"),
                                  Fruit(type: "orange"),
                                  Fruit(type: "banana"),
                                  Fruit(type: "banana"),
                                  Fruit(type: "peach")]
    
    var body: some View {
        List {
            // Since Fruit conforms to Identifiable, you do not need id:
            ForEach(fruits) { fruit in
                HStack {
                    Button {
                        fruits.removeAll(where: { [=11=].id == fruit.id })
                    } label: {
                        Image(systemName: "circle")
                            .imageScale(.large)
                            .foregroundColor(.accentColor)
                    }
                    .buttonStyle(PlainButtonStyle()) // This is necessary to capture the click
                    .frame(width: 40)
                    // .contentShape makes a larger tap area to take up the height of the row.
                    .contentShape(Rectangle())
                    // You can use fruit directly as it is a Fruit and an element of fruits
                    NavigationLink(destination: Text(fruit.type)) {
                        Text(fruit.type)
                    }
                }
            }
            // This is a standard delete. Try implementing it in your code. You will likely get a crash.
            .onDelete(perform: delete)
        }
    }
    
    func delete(at offsets: IndexSet) {
                fruits.remove(atOffsets: offsets)
    }
}