Noob in watchOS and SwiftUI. I have created a grid view with multiple buttons on it. Whenever a button is clicked, I wish to open a new view with navigation link. Since there are multiple buttons on the view, I have created a reusable view and having a hard time to implement navigation to next view. Below is my code:
Content View:
struct ContentView: View {
@Namespace var namespace
@State var selected: [MenuItem] = []
var body: some View {
MainMenuCircularGridView()
}
}
MainMenuCircularGridView:
struct MainMenuCircularGridView: View {
let columns = Array(repeating: GridItem(.fixed(72.0), spacing: 10), count: 2)
var body: some View {
NavigationView {
ScrollView {
let menuOptions = MenuOptions()
let menuOptionsAction = MenuActions()
LazyVGrid(columns: columns, spacing: 5) {
ForEach(menuOptions.menu) { item in
MenuItemCircularGridView(imageName: item.imageName, menuItemName: item.name, action: (menuOptionsAction.menuActions.first {$0.id == item.id})?.action ?? {})
}
}.padding()
}.navigationTitle("Sample App")
}
}
}
MenuItemCircularGridView:
struct MenuItemCircularGridView: View {
var imageName: String = ""
var menuItemName: String = ""
var action: () -> Void
var body: some View {
VStack {
CircularButtonWithImage(imageName:imageName,
imageBackgroundColor:Color(red: 34 / 255, green: 34 / 255, blue: 34 / 255),
imageForegroundColor: Color(red: 23 / 255, green: 121 / 255, blue: 232 / 255),
imageFrameWidth: 30.0,
imageFrameHeight: 30.0,
imagePadding: 10.0,
action: action)
Text(menuItemName).font(.system(size: 10))
}.padding(10)
}
}
CircularButtonWithImage:
struct CircularButtonWithImage: View {
var imageName: String = ""
var imageBackgroundColor: Color?
var imageForegroundColor: Color?
var imageFrameWidth: CGFloat = 0.0
var imageFrameHeight: CGFloat = 0.0
var imagePadding: CGFloat = 0.0
var action: () -> Void
var body: some View {
Button(action: { action() }) {
VStack{
Image(imageName)
.renderingMode(.template)
.resizable()
.scaledToFill()
.frame(width: imageFrameWidth, height: imageFrameHeight)
.padding(imagePadding)
.background(imageBackgroundColor)
.foregroundColor(imageForegroundColor)
.clipShape(Circle())
}
}
.buttonStyle(PlainButtonStyle())
}
}
This is kind of how my app looks:
Whenever I click on any of those buttons, I want to open a new view with navigation link. Something like below:
NavigationLink(destination: DetailView()) {
Text("Show Detail View")
}.navigationBarTitle("Navigation")
Since I have broken the view down into multiple reusable files, I am not sure where exactly should I put this logic to open a new view on button click.
Edit: Adding the hardcoded data that I am using. I was trying to pass navigation link as action to the button.
struct MenuOptions {
let menu: [MenuItem] = [
MenuItem(id: 0, name: "Option 1", imageName: "settings-gray"),
MenuItem(id: 1, name: "Option 2", imageName: "settings-gray"),
MenuItem(id: 2, name: "Option 3", imageName: "settings-gray"),
MenuItem(id: 3, name: "Set 1", imageName: "settings-gray"),
MenuItem(id: 4, name: "Set 2", imageName: "settings-gray"),
MenuItem(id: 5, name: "Settings", imageName: "settings-gray")
]
}
struct MenuActions {
let menuActions: [MenuItemAction] = [
MenuItemAction(id: 1, action: { NavigationLink("New View 1", destination: View1()) }),
MenuItemAction(id: 5, action: { NavigationLink("Settings", destination: SettingsView()) })
]
}
2
Answers
I realized me breaking down the views into different files was probably making things more complicated. Since I just have 6 buttons, I decided to keep the view into a single file and used your idea of creating MenuDestination for passing down the right view. Sharing my updated code below.
However the main reason I wanted to use NavigationLink is to get the back button button and navigation title name on the destination view to get back to the main menu. I am not seeing that back button with navigation title on top left of the destination view. Please do let me know if you have an idea of what I could be missing. My understanding is using NavigationLink automatically adds that to the destination view.
Updated code - MainMenuCircularGridViewNew:
Menu Destination:
A
NavigationLink
must be in view hierarchy, so instead of putting it in action we need to put some model there.A sketch of possible approach
MenuItemAction
take as argument binding to selection and internally assign destination to that bindingand
MenuItemAction
inited with case of correspondingMenuDestination
See also this post