Navigationlink question in Xcode 13.1 -- Blanks instead of links? - swiftui

Sorry for the newbie question, but I'm stuck on why Navigationlink produces no links at all. Xcode compiles, but there's a blank for where the links to the new views are. This particular view is View 3 from ContentView, so the structure is ContentView -> View 2 -> View 3 (trying to link to View 4).
struct MidnightView: View {
var hourItem: HoursItems
#State var showPreferencesView = false
#State var chosenVersion: Int = 0
#State var isPsalmsExpanded: Bool = false
#State var showLXX: Bool = false
var body: some View {
ScrollView (.vertical) {
VStack (alignment: .center) {
Group {
Text (hourItem.hourDescription)
.font(.headline)
Text ("Introduction to the \(hourItem.hourName)")
.font(.headline)
.bold()
.frame(maxWidth: .infinity, alignment: .center)
ForEach (tenthenou, id: \.self) {
Text ("\($0)")
Text ("\(doxasi)")
.italic()
}
}
.padding()
NavigationView {
List {
ForEach (midnightHours, id:\.id) {watch in
NavigationLink ("The \(watch.watchName)", destination: MidnightWatchView (midnightItem: watch, chosenVersion: self.chosenVersion, isPsalmsExpanded: self.isPsalmsExpanded, showLXX: self.showLXX))
}
}
}
Group {
Text ("Absolution of the \(hourItem.hourName)")
.font(.headline)
Text (absolutionTexts[(hourItem.hourName)] ?? " ")
Divider()
Text ("Conclusion of Every Hour")
.font(.headline)
Text (hourConclusion)
Divider()
Text (ourFather)
}
.padding()
}
}
.navigationBarTitle ("The Midnight Hour", displayMode: .automatic)
.navigationBarItems (trailing: Button (action: {self.showPreferencesView.toggle()}) {Text (psalmVersions[chosenVersion])}
.sheet(isPresented: $showPreferencesView) {PreferencesView(showPreferencesView: self.$showPreferencesView, chosenVersion: self.$chosenVersion, isPsalmsExpanded: self.$isPsalmsExpanded, showLXX: self.$showLXX)})
}
}

The cause of the NavigationLink not appearing is probably due to the fact that you're including a List within a ScrollView. Because List is a scrolling component as well, the sizing gets messed up and the List ends up with a height of 0. Remove the List { and corresponding } and your links should appear.
There are a number of other potential issues in your code (as I alluded to in my comment), including a NavigationView in the middle of a ScrollView. I'd remove that as well, as you probably have a NavigationView higher up in your view hierarchy already.

Related

Some NavigationLink are inaccessible

My SwiftUI TVOS app has two sets of NavigationLink. When both sets are present (not commented out), only one set is accessible to tap on. If I comment out one or the other set, the remaining NavigationLink is accessible to tap on and functions properly.
How can both sets of NavigationLink be accessible (can be interacted with)?
I've tried encapsulating my view in NavigationView and NavigationStack, neither behaved differently.
The view, as shown below, only the NavigationLinks in the ScrollView are accessible to interact with. The "Edit" NavigationLink cannot be selected to tap on. If I comment out the ScrollView NavigationLinks, then the "Edit" NavigationLink becomes accessible and functions correctly.
I've also tried replacing LazyVGrid with VStack to no effect.
import SwiftUI
struct TestSources: Hashable {
let id = UUID()
let name: String
}
struct SourcesView: View {
private var Sources = [TestSources(name: "Computer 1"), TestSources(name: "Computer 2")]
var columns: [GridItem] {
Array(repeating: .init(.adaptive(minimum: 200)), count: 2)
}
var body: some View {
NavigationStack {
VStack(alignment: .center) {
// Header
HStack(alignment: .center){
Label("Sources", systemImage: "externaldrive.connected.to.line.below")
.font(.headline)
.frame(maxWidth: .greatestFiniteMagnitude, alignment: .leading)
.padding(.all)
NavigationLink(destination: TestEditView()) {
Text("Edit")
}
}
Divider()
ScrollView(.vertical, showsIndicators: false) {
LazyVGrid(columns: columns, spacing: 10) {
ForEach(Sources.indices, id: \.self) { index in
NavigationLink(Sources[index].name ,value: Sources[index])
}.navigationDestination(for: TestSources.self) { source in
TestShareView(source: source)
}
.accentColor(Color.black)
.padding(Edge.Set.vertical, 20)
}
.padding(.horizontal)
}
}.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity,
alignment: .topLeading
)
}
}
}
struct TestEditView: View {
var body: some View {
Text("Edit")
}
}
struct TestShareView: View {
let source : TestSources
var body: some View {
Text(source.name)
}
}
I don't see any problem with the navigation links in this code.
I pasted the code into a new project and tweaked it a little to make it compile. As you can see, it just works.
My guess is that it might fail because something outside of this code. Maybe, it is within another NavigationStack or some structure that could increse it's navigation complexity?
Or as Yrb suggests, this force unwrapping could be failing because of null values?

Navigation Link Returning Back Two Levels on Exit

I am having trouble with a return from a navigation view within a tabbed view. My project has a Settings tab where the user may select via navigation link "View Entries". And from there another navigation link to "Add New Entry". Returning from Add New Entry should bring you to View Entries but instead is return another level to the Setting Menu.
I am seeing a warning on the console stating "trying to pop to a missing destination at /Library/Caches/com.apple...". Using the tabbed view sample code at SwiftUI NavigationView trying to pop to missing destination (Monoceros?) I no longer get the "pop-to-missing-destination" warning but I still have the same problem with the navigation return.
The sample code below is ready to run and test in Xcode 12.
In the sample code below, tap settings and select the navigation view "View Entries". This would be a screen where entries are displayed in a list. Tapping the plus button is where new entries could be added. The textfield on the "Add New Entry" screen doesn't do anything. Clicking the Save or Back buttons should return you to "View Entries" screen but instead returns you to the Setting Menu. The Save button uses presentationMode.wrappedValue.dismiss to dismiss the view.
The fact that two different version of the tab view logic didn't have any impact on my navigation view return logic leads me to believe that I just have some kind on plain old bug in my navigation view logic but I sure don't see one. The sample code below is using the standard tab view logic.
struct ContentView: View {
#State private var selection = 0
var body: some View {
NavigationView {
TabView (selection: $selection) {
HomeView()
.tabItem {
Label("Home", systemImage: "house")
}.tag(1)
AView()
.tabItem {
Label("A", systemImage: "a.circle")
}.tag(2)
BView()
.tabItem {
Label("B", systemImage: "b.circle")
}.tag(3)
SettingsView()
.tabItem {
Label("Settings", systemImage: "gearshape")
}.tag(4)
}
}
}
}
struct HomeView: View {
var body: some View {
Text("Home Screen")
}
}
struct AView: View {
var body: some View {
Text("A Screen")
}
}
struct BView: View {
var body: some View {
Text("B Screen")
}
}
struct SettingsView: View {
var body: some View {
VStack (alignment: .leading) {
List {
Text("Settings")
.font(.title)
.fontWeight(.bold)
.padding(.leading, 15)
NavigationLink(destination: SetAView()) {Text("View Entries")}
}
}
.font(.body)
}
}
struct SetAView: View {
var body: some View {
List {
Text("View Entries")
.padding(.vertical, 10)
Text("Normally entires would be displayed here")
Text("Should return here upon adding new entry")
.padding(.vertical, 10)
Text("Click the + button to add new entry")
}
.navigationBarItems(trailing: NavigationLink (destination: AddTestView()) {
Image(systemName: "plus")
.resizable()
.foregroundColor(Color(.systemBlue))
.frame(width: 18, height: 18)
} // body
)
}
}
struct AddTestView: View {
#Environment(\.presentationMode) var presentationMode
#State private var catSelect: String = ""
var body: some View {
NavigationView {
VStack {
Form {
Section {
TextField("Enter Entry Name", text: $catSelect)
.padding(.horizontal, 20)
.keyboardType(.default)
}
}
}
.navigationBarTitle(Text("Add new Entry"), displayMode: .inline)
.navigationViewStyle(StackNavigationViewStyle())
.navigationBarItems(trailing: Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text ("Save")
})
}
}
}
After considerable analysis I discovered in my actual code that I had two copies of NavigationView––nothing wrong with the TabView code. Removing the one NavigationView not in contentView then caused several functions from working so rebuilt them from scratch. Now have everything working with TabView and NaigationView including the back buttons.

Multiple Picker views: Inconsistent, cycle drop down lists

I have a form with three different picker views. When I run the app and click on one of the pickers, the drop-down content is populated from another picker and it spontaneously cycles through the other two picker contents before returning to the main view. I am gogin to kick myself when someone points to something very fundamental and basic.... but here is the code . And thanks in advance!
var body: some View {
Form{
VStack {
HStack {
Text("PaO2")
TextField("mmHg", text: $PaO2)
.keyboardType(.numberPad)
Spacer()
Text("O2(%)")
TextField("%", text: $FiO2)
.keyboardType(.numberPad)
}
Toggle("Mechnical Ventilation", isOn: $MV)
HStack {
Text("Platelets")
TextField("(x1000)", text: $Platelets)
.keyboardType(.numberPad)
}
Picker(selection: $GCSSelected, label: Text("Glasgow Coma Scale")) {
ForEach(0..<GCS.count){ index1 in
Text(self.GCS[index1]).tag(index1)
}
}
Spacer()
Picker(selection: $HDSelected, label: Text("MAP/use of vasoactive Rx")){
ForEach(0..<HD.count){ index2 in
Text(self.HD[index2]).tag(index2)
}
}
HStack{
Text("Bilirubin")
TextField("mg/dL", text: $Bili)
.keyboardType(.numbersAndPunctuation)
}
Picker(selection: $RenalSelected, label: Text("Creatinine or Urine output")){
ForEach(0..<Renal.count){ index3 in
Text(self.Renal[index3]).tag(index3)
}
}
}
}
}
}
The issue is due to used single view for entire Form content, but you should not, so
var body: some View {
Form{
VStack { // << remove this container and let every picker be in own row

SwiftUI: List rows get highlighted when interacting with other views if inside a TabView

If a List is placed along with other views within a VStack which defines one page within a TabView with PageTabViewStyle, interacting (tap, long pressing) with the other views causes all (visible) rows of the List to get highlighted.
The following View demonstrates this behaviour: tapping or long pressing the Button or the purple area (Color View) will cause the rows in the List to get highlighted (Xcode 12.1 & iOS 14.1).
struct ContentView: View {
var body: some View {
TabView {
VStack {
List {
Text("Row 0")
Text("Row 1")
Text("Row 2")
}
.listStyle(InsetGroupedListStyle())
Spacer()
Button(action: { print("tapped")}, label: { Text("Button") } )
.padding(.vertical, 80)
Spacer()
Color.purple
}
Text("Second Page")
}
.tabViewStyle(PageTabViewStyle())
}
}
I assume this is a bug and have already submitted feedback, but was wondering if there is a workaround while it's not fixed.
wondering if there is a workaround while it's not fixed.
After some investigation & testing the only workaround I see is to use scroll view instead
TabView {
VStack {
ScrollView { // << here
Text("Row 0")
Text("Row 1")
Text("Row 2")
}
Note: of course it might require some manual formatting & layout inside scroll view, but there is no such bug.

It is possible to make NavigationView title clickable in SwiftUI?

I want to add action on tap to NavigationView title. Is it possible in SwiftUI?
If you can use the .inline title display mode, you can use the new toolbar API introduced in iOS 14 to overwrite the title displayed in the navigation bar.
See below a simple example, where tapping the title is incrementing the counter:
struct ContentView: View {
#State private var counter = 0
var body: some View {
NavigationView {
VStack {
Text("Main content")
Text("\(counter)")
.font(.title)
}
.navigationBarTitleDisplayMode(.inline)
.toolbar(content: {
ToolbarItem(placement: .principal) {
Text("Press here")
.bold()
.onTapGesture {
counter += 1
}
}
})
}
}
}