Swift Navigation Link problems - swift

I am having problems with NavigationLink in Swift and iOS 14. This is a known issue, however the problem solvers that I saw, are not sufficient. I found out that when a button with a NavigationLink is initialized early, it works and when you enter the page, you have the "go back" button. However, when the navigation link is in the middle, you are not able to go back when you enter the page and must close the app to go to the main screen again.
This is the code I am using:
HStack {
Button(action: {
if let url = URL(string: "I blacked this out to make no advert here") {
UIApplication.shared.open(url)
}
}){
Text("Rate App").foregroundColor(.gray)
}.modifier(navigationButtonViewStyle())
Spacer()
// this navigation link works fine
NavigationLink(destination: HelpView()) {
Text("FAQ").foregroundColor(.gray)
}.modifier(navigationButtonViewStyle())
}.padding(.horizontal, 20)
VStack {
Text("λSET")
.font(.largeTitle)
.fontWeight(.heavy)
.bold()
.padding(.top, 50)
.onAppear(perform: prepareHaptics)
.animation(.linear)
Text("λudio System Engineer Tools")
.fontWeight(.light)
.animation(.linear(duration: 0.5))
HStack {
Spacer()
// this navigation link is not showing the go back button when pressed and directed to the new screen
NavigationLink(destination: AboutView()) {
Text("About λSET")
.fontWeight(.heavy)
.bold()
}
Spacer()
}.modifier(calcTitleViewStyle())
.padding(.top, 20)
.padding(.bottom, 60)
}
I am not sure what the problem is, but am curious what this could be. I am working on a workaround, but I would love to solve the problem at its roots.
Thanks!

Fixed it myself by explicitly setting the .NavigationBar to true to force swift to load it. This was not needed in other pages, but I am now doing to make sure IOS14 accepts it, since a few things have been changed there.

Related

Unable to create list of string SwiftUI from json response

I have a list of remarks which I receive from an API call. I have created a loop to create TEXT from the remarks but the texts do not appear in the application. Please check the code.
I have also checked the debugger and it shows a the string present there but it doesn't create the text.
VStack{
Text("Remarks")
.padding(.horizontal, 15)
.font(.title2)
if(currentFrResponse.remarks != nil){
Text("fine")
List(currentFrResponse.remarks!, id:\.self){ currentRemark in
Text("Test")
Text(currentRemark)
.bold()
.padding()
}
}
}
debugger result
Let me know if you need any more details
I have tried this code in my project and it's working fine, as per my knowledge this issue is something else related to other component or view that you are using in the same controller, But if you want you can try creating individual view for this list and then use it.
var body: some View {
VStack{
Text("Remarks")
.padding(.horizontal, 15)
.font(.title2)
List(landmarks, id:\.self){ currentRemark in
VStack{
Text(currentRemark.name)
.bold()
.padding()
}.padding()
}
}
}

SwiftUI Finding Solution for Button overlay on Image

I overlayed a button/text on the image, but the button didnt respond. Is there any solution?
It seems like the hidden navigation bar view is blocking the button or the image is blocking the touch gesture. How should I fix this?
struct Tutorial: View {
let dataModel = DataModel()
#State var messageIndex = 0
var body: some View{
ZStack{
Image("Tutorial UI")
.resizable()
.scaledToFill()
.overlay(
VStack(spacing:20){
VStack(spacing:30){
HStack{
Spacer()
Text("Next")
.foregroundColor(.blue)
.fontWeight(.black)
.onTapGesture(count:1) {
if self.messageIndex != 4{
self.messageIndex += 1
}else{
self.messageIndex = 0
}
}
}
Text(dataModel.tutorialMessage[messageIndex][0])
.fontWeight(.black)
.font(.largeTitle)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
}.padding()
Text(dataModel.tutorialMessage[messageIndex][1])
.font(.title)
Spacer()
}.padding(.horizontal, 48)
.padding(.top, 50)
)
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity,
alignment: .center)
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
}
What #Asperi was getting at is you have provided a code snippet that depends upon a model we know nothing about. When you post code, you should post a simplified version. In this case I took your code and swapped out your data model for a simple array. I also downloaded an image to use from NASA's Image of the Day to use. And, Asperi nailed the problem with his second question...
Looking at it, the first thing that struck me is you are trying too hard to position things just so in SwiftUI. It doesn't work that way. And that led to your problems. I pulled out your frames which actually don't do anything in this layout. I also pulled out the specific padding amounts. I then pulled the Spacer() out that was in your HStack, and your "Next" button appeared on the screen. I suspect that setting the image as .scaledToFill() and an image that is not in the same dimensions of the screen caused the view to be larger than the screen you could see. Putting the Spacer() in caused your "Next" button to move all of the way to the right, which was off screen. Once I could see it, I was able to click it and it worked fine.
You have an extremely complicated structure that produces a pretty simple layout. Next time, start small and only add what you need. Less layout is better in SwiftUI, or you end up with unintended consequences. Try changing the HStack in your Overlay to the following and then work from there, one step at a time:
HStack{
Text("Next")
.foregroundColor(.blue)
.fontWeight(.black)
.onTapGesture(count:1) {
if self.messageIndex != 4{
self.messageIndex += 1
}else{
self.messageIndex = 0
}
}
}
Remember, in SwiftUI the Child View determines its own size. Don't try to force things from a Parent.

tvOS Button inside NavigationLink is not Working

I have built an iOS app using swift and swiftui and now I am working on the tvOS version of the app. However, I have a couple of issues. One of the issues is still unresolved: tvOS Textfield Transparent Background
I was creating a login page and I realized that the button inside the NavigationLink was not doing anything. Then to test and identify the issue I created a simple button as follows:
Button(action: {
print("Login pressed")
}) {
Text("Login")
.frame(width:300, height: 35)
}
.background(Color.blue)
.foregroundColor(Color.white)
Output when clicked on:
Login pressed
And it looks like this:
And it looks like this when focused:
But when I insert that button inside a NavigationLink, Navigation like acts like a button and this button does nothing.
The code is like that:
NavigationLink(destination: mainScene(), tag:1, selection: $selection) {
Button(action: {
print("Login pressed")
self.selection = 1
}) {
Text("Login")
.frame(width:300, height: 35)
}
.background(Color.blue)
.foregroundColor(Color.white)
}
In the iOS, I have a similar code, and it does not navigate until everything in the button action is executed and selection is equal to 1. But in this, it does not execute anything and it just directly navigates to the next page. The button looks like this when I embed it in the NavigationLink:
As you can see there is white space around the original login button and the focus is on that white space. And when clicked on it navigates. It looks like the NavigationLink acts like a button but it also prevents the button action to be executed. I am having these kind of problems that are mainly caused by the focus. For Example in the images above, as you can see the shape and the color of the button changes when the focus is on but I want to control it. However, I don't know how I can play with on focus design of the items.
Try the following
Button(action: {
print("Login pressed")
self.selection = 1
}) {
Text("Login")
.frame(width:300, height: 35)
}
.background(Color.blue)
.foregroundColor(Color.white)
.background(NavigationLink(destination: mainScene(), tag:1,
selection: $selection) { EmptyView() })
Try This:
NavigationLink(destination: mainScene(), tag:1, selection: $selection) {
Button(action: {
print("Login pressed")
self.selection = 1
}) {
Text("Login")
.frame(width:300, height: 35)
}
.background(Color.blue)
.foregroundColor(Color.white)
}.buttonStyle(PlainButtonStyle())

HStack inside ScrollView animates weirdly when opening view

So I was trying to implement expanding/contracting rows in a for each embedded in a list view and it turns out the list view cells don't animate smoothly. After checking out this tutorial, it suggests using a scrollview with a foreach because it animates smoother. The expanding/contracting works fine, but there unintended side effects only when I first open the page. The HStack appears to start flattened on the left side of the view and animates expanding to its normal starting position. I've slowed down the animations in the video so it's easier to see, and I removed the ForEach since it doesn't seem to be the cause of the problems. I don't know what is causing this and google searching has yielded no answers. Does anyone here have an answer or at least some advice? Much appreciated
#State var showTemp: Bool = false
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
HStack(alignment: .top) {
Text("Hello")
.font(.system(size: 32))
if showTemp {
VStack {
Text("Middle 1")
Text("Middle 2")
Text("Middle 3")
Text("Middle 4")
Text("Middle 5")
}
}
Spacer()
Text("Goodbye")
}
.border(Color.black, width: 2)
.onTapGesture {
self.showTemp.toggle()
}
.background(Color.blue)
.animation(.default)
}
.background(Color.green)
.onAppear(perform: loadMethod)
}
It seems I've answered my own question after I looked at the problem from a different angle. Using GeogetryReader and setting the frame width of the HStack to geometry.size.width fixed it.
I think this works because without specifying the width, the HStack fills as much area as it can. For some reason, it starts smushed when the view is loaded and then expands to fill its area, which I guess isn't visible unless you apply an animation to it.
Trying to be helpful here, I don't want to be one of those people who answers their own questions but doesn't show what the answer it.

List inside ScrollView is not displayed on WatchOs

I have a list inside a scrollview and it is not displaying below the image and the buttons. I've also tried to put the list and other items inside of a VStack and that allows me to see one item of the list at the time opposed to scrolling past the Image and buttons to show the whole list.
ScrollView{
Image(uiImage: self.image)
.resizable()
.frame(width: 80, height: 80)
.scaledToFit()
Text("\(name)")
.lineLimit(2)
HStack{
Button(action: {
print("button1")
}){
Image(systemName: "pencil")
}
Button(action: {
print("button 2")
}){
Image(systemName: "trash")
}
}
List{
ForEach(self.items, id: \.self) { item in
VStack{
Text(item.name)
.font(.headline)
.lineLimit(1)
Text(item.subname)
.font(.subheadline)
.lineLimit(1)
}
}
}
}
.navigationBarTitle(Text("Tittle"))
.edgesIgnoringSafeArea(.bottom)
Ive also tried to add .frame( minHeight: 0, maxHeight: .infinity)
to the list to force it to have its whole height and that did not work either. Any suggestions or might this be a swiftUI bug ?
EDIT
I just realized Im getting this error when scrolling:
APPNAME Watch Extension[336:60406] [detents] could not play detent NO, 2, Error Domain=NSOSStatusErrorDomain Code=-536870187 "(null)", (
{
Gain = "0.01799999922513962";
OutputType = 0;
SlotIndex = 4;
},
{
Gain = "0.6000000238418579";
OutputType = 1;
SlotIndex = 5;
}
)
Indicate some height for your List like
List{
ForEach(self.items, id: \.self) { item in
VStack{
Text(item.name)
.font(.headline)
.lineLimit(1)
Text(item.subname)
.font(.subheadline)
.lineLimit(1)
}
}
}.frame(minHeight: 200, maxHeight: .infinity)
Have you tried putting the List inside of a GeometryReader and setting the frame there?
I got the same error with UIKit. The error message is related to haptic feedback, see here.
It says that a haptic feedback could not be played, probably type 2, i.e. directionDown, see here.
Since my code does not call play(_:), it must be called by watchOS itself.
The reason for the error might be very fast scrolling, which could result in too frequent calls to play(_:) that cannot be handled properly. The docs say:
Do not call this method multiple times in quick succession. If the
haptic engine is already engaged when you call this method, the system
stops the current feedback and imposes a minimum delay of 100
milliseconds before engaging the engine to generate the new feedback.
If this is really an effect of watchOS, I guess you cannot do anything to avoid the error.