SwiftUI NavigationView layout issues - swiftui

My NavigationView and Title when using SwiftUI never appear where I'd expect them to appear when run on a device or simulator. I want them to be pretty much under the back button that is top left but when run on a device or simulator it goes quite far down the page, here is a screenshot of my simulator resized beside the preview and you can see how different this is.
Here is my code:
import SwiftUI
struct DetailView: View {
let tarot: Tarot
var body: some View {
NavigationView {
VStack() {
Image(tarot.tarotImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.padding(.init(top: 80, leading: 30, bottom: 80, trailing: 30))
Text(tarot.tarotDescription)
.padding(.horizontal)
}
.navigationBarTitle(tarot.tarotName, displayMode: .automatic)
}
}
}
struct DetailView_Previews: PreviewProvider {
static var previews: some View {
DetailView(tarot: cardsArray[0])
}
}

You shouldn't have more than one NavigationView in your navigation stack.
Try to remove the NavigationView from your DetailView:
struct DetailView: View {
let tarot: Tarot
var body: some View {
VStack {
Image(tarot.tarotImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 200, height: 200)
.padding(.init(top: 80, leading: 30, bottom: 80, trailing: 30))
Text(tarot.tarotDescription)
.padding(.horizontal)
}
.navigationBarTitle(tarot.tarotName, displayMode: .automatic)
}
}

Related

SwiftUI ZStack not showing bottom element with List

When put Image to the bottom of ZStack , image just not showing
struct ContentView: View {
var body: some View {
VStack{
ZStack{
Image(systemName:"folder") // not showing
.resizable()
.scaledToFit()
.frame(width: 70, height: 70, alignment: .center)
List {
ForEach(1...8, id: \.self){ i in
Text("ROW \(i)")
}
}
}
}
}
}
and image will show if it's on top.
struct ContentView: View {
var body: some View {
VStack{
ZStack{
List {
ForEach(1...8, id: \.self){ i in
Text("ROW \(i)")
}
}
Image(systemName:"folder") // This will show
.resizable()
.scaledToFit()
.frame(width: 70, height: 70, alignment: .center)
}
}
}
}
How can I show the image at bottom, and hide it when List scroll to the top of image?
You can achieve the result you are looking for by changing the background of the list like this:
struct ContentView: View {
var body: some View {
List {
ForEach(1...8, id: \.self){ i in
Text("ROW \(i)")
}
}
.background(
ZStack {
// Apply the default list background color in case you want it
Color(UIColor.systemGroupedBackground)
.edgesIgnoringSafeArea(.all)
Image(systemName: "folder")
.resizable()
.scaledToFit()
.frame(width: 70, height: 70, alignment: .center)
}
)
.scrollContentBackground(.hidden)
}
}

Utilize HStack to confirm to logo and skip text

Does anyone know how to make the following view in SwiftUI?
HStack:
[ blank logo(centered) Skip(text)]
So I have the following HStack:
Zstack(alignment: .topLeading) {
VStack{
HStack {
Image("onboarding-logo")
.resizable()
.scaledToFit()
.frame(width: 150.0, height: 150.0)
.padding(.top, 35)
}
}
}
Does anyone know how I can have a "Skip" text in the top right corner of the screen, but also keep my logo centered and not have anything on the left side? I've tried Spacers and all, but I'm having no luck.
I would like to click "Skip" and then lead to another view.
There are many ways to achieve this. Here I have used LazyVGrid since other answers based on Stacks
struct ContentView: View {
var body: some View {
VStack {
LazyVGrid(columns: [GridItem(), GridItem(), GridItem()], content: {
Spacer()
Image(systemName: "star.fill")
.frame(width: 150, height: 150, alignment: .center)
.border(.gray)
Button(action: {
}, label: {
Text("Skip")
})
})
.border(.gray)
Spacer()
}
}
}
Is this the screen configuration you want?
The Zstack is used to center the Hstack into which the image is placed, and the new HStack uses a spacer to move the Text to the right.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
VStack {
HStack(alignment: .center) {
Image("farnsworth")
.resizable()
.scaledToFit()
.frame(width: 150.0, height: 150.0)
}
Spacer()
}
VStack {
HStack {
Spacer()
Button {
// do Something...
} label: {
Text("Skip>>")
.padding(.top, 10)
}
}
Spacer()
}
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

How to use scaleEffect with TextEditor in SwiftUI?

I want to use scaleEffect to scale a TextEditor contained in a VStack. When not scaled the text editor is very normal. But After scaling the editor can not be edited normally as the cursor can not be placed in the right place. Here is the code:
import SwiftUI
struct DemoTextView: View {
#State var text: String = ""
#State var scale: Double = 1
var body: some View {
VStack {
Spacer()
VStack {
TextEditor(text: $text)
.frame(width: 100, height: 100, alignment: .top)
.border(Color.red)
}
.scaleEffect(scale)
Spacer()
HStack {
Slider(value: $scale, in: 0.25...4)
Text("\(scale)")
}
.padding()
}
.frame(width: 500, height: 500, alignment: .center)
}
}
struct DemoTextView_Previews: PreviewProvider {
static var previews: some View {
DemoTextView()
}
}
And the screenshot of the wired behavior:
Anyone knows how to make the scaling of TextEditor works?

SwiftUI height animation of a text frame when #ObservedObject change

I try to make a smooth animation when the NetStatus change but it's not working like i want.
I want to get the same effect as when i press the button with the toggle animation. The commented button animation is working great and i try to replicate it with the scaling of the height of the text frame.
The commented button code is just for a working example of the animation effect that i want (expand and close gracefully), i don't need this code.
How can i do that?
import SwiftUI
struct NoNetwork: View {
let screenSize: CGRect = UIScreen.main.bounds
#ObservedObject var online = NetStatus()
var body: some View {
VStack{
Text("NoNetworkTitle")
.fontWeight(.bold)
.foregroundColor(Color.white)
.frame(width: screenSize.width, height: self.online.connected ? 0 : 40, alignment: .center)
// .animation(.easeIn(duration: 5))
.background(Color.red)
// Button(action: {
// withAnimation {
// self.online.connected.toggle()
// }
// }, label: {
// Text("Animate")
// })
}
}
}
struct NoNetwork_Previews: PreviewProvider {
static var previews: some View {
NoNetwork()
}
}
To animate when online.connected changes, put the .animation modifier on the VStack:
VStack{
Text("NoNetworkTitle")
.fontWeight(.bold)
.foregroundColor(Color.white)
.frame(width: screenSize.width, height: self.online.connected ? 0 : 40, alignment: .center)
.background(Color.red)
Button(action: {
self.online.connected.toggle()
}, label: {
Text("Animate")
})
}
.animation(.easeInOut(duration: 0.5))
This will animate the other views in the VStack as the Text appears and disappears.

SwiftUI NavigationLink how to get to another SwiftUI page?

I'm trying to get from one SwiftUI view to another SwiftUI view and I'm using a NavigationLink as per the code below, but I'm getting the error: Cannot invoke initializer for type 'NavigationLink<_, _>' with an argument list of type '(destination: PlaylistTable)'
Below is my code for the button which triggers the link to the next view:
struct MusicButton: View {
var body: some View {
NavigationView {
Button(action: {
NavigationLink(destination: PlaylistTable())
})
{ Image(systemName: "music.note.list")
.resizable()
.foregroundColor(Color.white)
.frame(width: 25, height: 25, alignment: .center)
.aspectRatio(contentMode: .fit)
.font(Font.title.weight(.ultraLight))
}
}
}
}
Don't put NavigationLink inside a Button will solve your problem:
NavigationView {
NavigationLink(destination: PlaylistTable())
{ Image(systemName: "music.note.list")
.resizable()
.foregroundColor(Color.white)
.frame(width: 25, height: 25, alignment: .center)
.aspectRatio(contentMode: .fit)
.font(Font.title.weight(.ultraLight))
}
}
If you want to use the button, then move the navigation link to the background.
struct MusicButton: View {
#State var isActive = false
var body: some View {
NavigationView {
Button(action: {
isActive.toggle()
})
{ Image(systemName: "music.note.list")
.resizable()
.foregroundColor(Color.white)
.frame(width: 25, height: 25, alignment: .center)
.aspectRatio(contentMode: .fit)
.font(Font.title.weight(.ultraLight))
}
}
.background(
NavigationLink(destination: PlaylistTable(), isActive: $isActive) {EmptyView()}
)
}
}