Button gets overlapped by navigation bar SwiftUI watchOS - swift

I have recently been developing an app for Apple Watch using SwiftUI. I have integrated NavigationView and embedded another View into it. This embedded view has got few buttons, which I can't figure out how to size properly. The top row is overlapped by navigation bar. Is there some workaround how to size it properly? I have tried using Text instead of button and with it it works fine.
This is structure of my main view:
NavigationView {
ScrollView(.vertical) {
NavigationLink(destination: InputView()) {
Text("Click here to get view")
}
}
}
This is structure of InputView:
var body: some View {
NavigationView {
VStack(spacing: 0) {
ForEach(0..<4) { rowIndex in
HStack {
ForEach(0..<3) { columnIndex in
let buttonID = rowIndex*3 + columnIndex
Button("\(buttonID)") {
print(buttonID)
}
}
}
}
}
}
}
Here's an image that shows the functionality

Related

SwiftUI navigation works on iOS but fails on macOS

I have an iOS SwiftUI app that works fine on iPhone and iPad, but when compiled for native macOS the navigation links are disabled. Code is below. Briefly, the FirstView is a NavigationView containing a List of NavigationLinks. These work, and link to a DetailView that contains a next level of NavigationLinks presented as Images.
On iOS, these images are active blue that when clicked, go to a FinalView.
On macOS, these images are inactive: Presented as gray, and don't have any click-ability.
Why do these appear differently on the two OS's? How to fix the macOS version so that it navigates? Thanks in advance
import SwiftUI
struct TNode { // simple data struct that just carries name and ID
public let id = UUID()
public let name : String
init( _ name:String) {
self.name = name
}
}
// starting view
struct FirstView: View {
init () {
// provide some sample data
nodes = [TNode("node 1"), TNode("node 2")]
}
#State private var nodes : [TNode]
var body: some View {
NavigationView {
List {
ForEach(nodes, id:\.id) { (node) in
// where to go when selected
NavigationLink(destination:
DetailView(displayNode: node)
){ // display names for selection in the sidebar
VStack {
Text(node.name)
}
}
}
}
}
}
}
struct DetailView: View {
let displayNode : TNode
var body: some View {
VStack(alignment: .leading) {
Text(displayNode.name)
HStack{
// this is what doesn't work on macOS
NavigationLink(destination: FinalView()) {
Image(systemName:"figure.stand.line.dotted.figure.stand")
}
NavigationLink(destination: FinalView()) {
Image(systemName:"square.and.pencil")
}
}
}
}
}
struct FinalView : View {
var body : some View {
Text("Got to final view OK")
}
}
Behavior on macOS:
Xcode 13.4.1, macOS Monterey 12.4
Embed the VStack of the DetailView in a NavigationView. Remember that iOS is different than macOS.
In iOS you didn't need to wrap the child View of in a NavigationView because it's a child. With macOS this a standalone View.
Remove Stack in Navigation link :
){ // display names for selection in the sidebar
// Remove VStack VStack {
Text(node.name)
// }
}

navigationBarHidden broken with SwiftUI Xcode beta?

I'm trying out SwiftUI for an demo project and my navigationBarHidden fails on one computer while succeeding on another. They are both on the Xcode Beta.
It is a very simple transit app with a tab bar and navigation view as its root. The detail view has a custom header with floating buttons for backward navigation as well as a "more" menu. I want to hide the navigation bar to make this as visually appealing as possible, but right now I can't get the nav bar to disappear one one of my machines.
struct Dashboard: View {
var body: some View {
NavigationView {
TabView {
SavedStopsBrowser().tabItem {
Label(Verbiage.shared.saved, systemImage: "star")
}
StopSearcher().tabItem {
Label(Verbiage.shared.search, systemImage: "magnifyingglass")
}
}.accentColor(AppColors.primary)
}
}
}
The detail view of the saved stop is as such:
struct StopViewer: View {
#Environment(\.presentationMode) var presentation
let stop: TrainStop
init(stop: TrainStop) {
self.stop = stop
}
var body: some View {
GeometryReader { geometry in
ScrollView {
VStack(spacing: 0) {
CollapseableStopHeader(stop: stop, geometry: geometry, backButtonAction: {
self.presentation.wrappedValue.dismiss()
}, moreButtonAction: {
print("User did press more button")
})
TransitLineCatalog(lines: stop.associatedTrainLines)
.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 10))
}
}
.navigationBarHidden(true)
.ignoresSafeArea(edges: .top)
}
}
}
Any thoughts or suggestions as a way to make this work? Am I doing something horribly wrong?

How can I change my SwiftUI background without losing the navigation bar UI?

I'm trying to change my View background colour to a specific color, however, whenever I add it using the basic Zstack way, it loses the navigation bar UI. (See pictures)
EDITED CODE
This method is not working for me:
var body: some View {
ZStack{
Color("Background")
.edgesIgnoringSafeArea(.vertical)
VStack {
ScrollView {
ZStack {
VStack {
HStack{
VStack (alignment: .leading) {
Text("")
}
}
}
}
}
Text("")
}
}
}
Current UI with simple ZStack:
Desired UI:
How do I change my background color in SwiftUI without losing the navigation bar UI?
At this period of SwiftUI evolution it is possible only as workaround via UIKit
Here is a demo of possible approach (tested with Xcode 12.1 / iOS 14.1):
var body: some View {
NavigationView {
VStack {
ScrollView {
VStack {
ForEach(0..<50) {
Text("Item \($0)")
}
}
}
Text("Test").navigationTitle("Test")
.background(UINavigationConfiguration { nc in
nc.topViewController?.view.backgroundColor = .yellow
})
}
}
}
Note: the UINavigationConfiguration is taken from next my answer https://stackoverflow.com/a/65404368/12299030

Is there a way to navigate from detail view to inner detail view in SwiftUI

I'm working on a macOS app using SwiftUI. In the main view of the app, I have a list, with each element acting as a NavigationLink. In the destination view of each element, I want to have a NavigationLink to a third view that covers all the second view (like in WhatsApp for Mac or in iOS).
The problem is that when I'm clicking on the NavigationLink, nothing happens (the button appears as a disabled button). Also, I tried to have the navigation link activated by a #State, but the third view appears as a popover.
The maim view:
NavigationView {
List {
ForEach(elements) { elements in {
NavigationLink(destination: FirstDetailView(element: element)) {
ElementRowView(element: element)
.accentColor(listAccentColor)
}
}
}
}
The first detail view:
Group {
GeometryReader { geo in
List {
ForEach(elements) { element in
InnerElementView(element: element)
}
}
}
.toolbar {
ToolbarItem {
Button {
showThirdView.toggle()
} label: {
Image(systemName: "square.and.pencil")
.font(.system(size: ListView.buttonSize))
}
}
}
NavigationLink(destination: ThiredView(),
isActive: $showThirdView) { EmptyView() }
.hidden()
}
macOS 11.0.1 (RC2)
Xcode 12.2 (latest from the App Store)
When I'm using the link as the button:
When I'm using a var to activate the link:

SwiftUI: Dismiss View Within macOS NavigationView

As detailed here (on an iOS topic), the following code can be used to make a SwiftUI View dismiss itself:
#Environment(\.presentationMode) var presentationMode
// ...
presentationMode.wrappedValue.dismiss()
However, this approach doesn't work for a native (not Catalyst) macOS NavigationView setup (such as the below), where the selected view is displayed alongside the List.
Ideally, when any of these sub-views use the above, the list would go back to having nothing selected (like when it first launched); however, the dismiss function appears to do nothing: the view remains exactly the same.
Is this a bug, or expected macOS behaviour?
Is there another approach that can be used instead?
struct HelpView: View {
var body: some View {
NavigationView {
List {
NavigationLink(destination:
AboutAppView()
) {
Text("About this App")
}
NavigationLink(destination:
Text("Here’s a User Guide")
) {
Text("User Guide")
}
}
}
}
}
struct AboutAppView: View {
#Environment(\.presentationMode) var presentationMode
public var body: some View {
Button(action: {
self.dismissSelf()
}) {
Text("Dismiss Me!")
}
}
private func dismissSelf() {
presentationMode.wrappedValue.dismiss()
}
}
FYI: The real intent is for less direct scenarios (such as triggering from an Alert upon completion of a task); the button setup here is just for simplicity.
The solution here is simple. Do not use Navigation View where you need to dismiss the view.
Check the example given by Apple https://developer.apple.com/tutorials/swiftui/creating-a-macos-app
If you need dismissable view, there is 2 way.
Create a new modal window (This is more complicated)
Use sheet.
Following is implimenation fo sheet in macOS with SwiftUI
struct HelpView: View {
#State private var showModal = false
var body: some View {
NavigationView {
List {
NavigationLink(destination:
VStack {
Button("About"){ self.showModal.toggle() }
Text("Here’s a User Guide")
}
) {
Text("User Guide")
}
}
}
.sheet(isPresented: $showModal) {
AboutAppView(showModal: self.$showModal)
}
}
}
struct AboutAppView: View {
#Binding var showModal: Bool
public var body: some View {
Button(action: {
self.showModal.toggle()
}) {
Text("Dismiss Me!")
}
}
}
There is also a 3rd option to use ZStack to create a Modal Card in RootView and change opacity to show and hide with dynamic data.