I have a button that I would like to link to another view upon clicking on it. I was told to put it inside a NavigationLink, use .borderless button style, but it activates outside of its area on the entire list row. I experimented with using navigation view or disabling the navigationlink among other suggestions but it doesn't fix the problem or just messes up my view so I must be doing something wrong.
Here is the list item view
struct NodeListItem: View {
var body: some View {
LazyVStack(alignment: .leading) {
//has more information up here I don't think is relevant
HStack {
NavigationLink(destination: UserMessageList(user: node.user!)) {
Button("DM") {
//don't actually need it to do anything besides changing views
}
//.borderless does nothing I want it to have a border
.buttonStyle(.borderedProminent)
}
}
}
}
Here is my list view
struct NodeList: View {
var body: some View {
NavigationStack {
List(nodes, id: \.self) { node in
NodeListItem(node: node)
.contextMenu {
Button {
node.user!.mute = !node.user!.mute
} label: {
Label(node.user!.mute ? "Show DM Alerts" : "Hide DM Alerts", systemImage: node.user!.mute ? "bell" : "bell.slash")
}
if bleManager.connectedPeripheral != nil {
Button (role: .destructive) {
deleteNodeId = node.num
isPresentingDeleteNodeAlert = true
} label: {
Label("Delete Node", systemImage: "trash")
}
}
}
}
.listStyle(.plain)
}
}
Any help/suggestions are appreciated!
You should not use a NavigationLink
. You should do the navigation programmatically in the button's action closure.
Assuming the type of nodes
is [Node]
, you can add a @State
representing the navigation path like this:
@State private var path: [Node] = []
let nodes = [...]
var body: some View {
NavigationStack(path: $path) {
List(nodes, id: \.self) { node in
NodeListItem(node: node) {
// programmatic navigation
path.append(node)
}
.contextMenu { ... }
}
.navigationDestination(for: Node.self) { node in
UserMessageList(user: node.user!)
}
}
}
Note that the navigation destination of UserMessageList
is declared on the List
, instead of each individual NodeListItem
.
NodeListItem
should be changed to take a closure for its button's action:
struct NodeListItem: View {
let node: Node
let buttonAction: () -> Void
var body: some View {
LazyVStack(alignment: .leading) {
// ...
HStack {
// ...
Button("DM") {
buttonAction()
}
.buttonStyle(.borderedProminent)
}
}
}
}
Of course, you can also pass a @Binding
of the navigation path, and do path.append
in NodeListItem
:
struct NodeListItem: View {
let node: Node
@Binding var path: [Node]
var body: some View {
LazyVStack(alignment: .leading) {
// ...
HStack {
// ...
Button("DM") {
path.append(node)
}
.buttonStyle(.borderedProminent)
}
}
}
}
// ...
NodeListItem(node: node, path: $path)
Personally I think the former makes more sense.