Navigation View not working properly in SwiftUI on iPad - ios

I am trying to create an navigation view that works on both iPhone and iPad. Currently I have it working on the iPhone however when running it on the iPad the navigation view doesnt present my main view properly. See below:
This is when I load the app
If I press products (top left) it opens up the products tab.
When I click on a product it goes to this screen
If I click Product 1 (seen on 3rd image) It opens all the details into another navigation bar.
What I am trying to achieve is that image 4 isn't in a navigation tab and instead it is the full screen. I tried removing NavigationView from my code which seems to fix the problem and makes it full screen. However, I then lose the navigation view buttons to allow the user to view other products.
Here is a shortened version my code (without all the text/image details):
var body: some View {
NavigationView {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .center, spacing: 20) {
ProductHeaderView(product: product)
VStack(alignment: .leading, spacing: 15) {
Text(product.title)
.font(.largeTitle)
.fontWeight(.heavy)
.foregroundColor(product.gradientColors[1])
Text(product.headline)
.font(.headline)
.multilineTextAlignment(.leading)
}
.padding(.horizontal, 20)
.frame(maxWidth: 640, alignment: .center)
}
.navigationBarTitle(product.title, displayMode: .inline)
.navigationBarHidden(true)
}
.edgesIgnoringSafeArea(.top)
}
}
}
Thank you in advance for your help :)
EDIT:
Here is the ProductHeaderView.swift code:
var body: some View {
ZStack {
LinearGradient(gradient: Gradient(colors: product.gradientColors), startPoint: .topLeading, endPoint: .bottomTrailing)
TabView{
ForEach(0..<product.images.count, id: \.self) { item in
Image(product.images[item])
.resizable()
.scaledToFit()
.shadow(color: Color(red: 0, green: 0, blue: 0, opacity: 0.15), radius: 8, x: 6, y: 8)
.scaleEffect(isAnimatingImage ? 1.0 : 0.6)
}//: FOR LOOP
}//: TAB VIEW
.tabViewStyle(PageTabViewStyle())
.padding(.vertical, 0)
} //: ZSTACK
.frame(height: 414)
.onAppear(){
withAnimation(.easeOut(duration: 0.5)){
isAnimatingImage = true
}
}
}
Example project: https://github.com/spoax94/productsMinimal.git

Just add this line as a modifier in your NavigationView:
.navigationViewStyle(StackNavigationViewStyle())

As I commented there should be only one NavigationView, so here fixed ProductDetailView with removed redundant NavigationView.
Tested with Xcode 12
struct ProductDetailView: View {
var product: Product
var products: [Product] = productData
#State var showingPreview = false
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .center, spacing: 20) {
ProductHeaderView(product: product)
VStack(alignment: .leading, spacing: 15) {
Text(product.title)
.font(.largeTitle)
.fontWeight(.heavy)
Text(product.headline)
.font(.headline)
.multilineTextAlignment(.leading)
Text("Learn More About \(product.title)".uppercased())
.fontWeight(.bold)
.padding(0)
Text(product.description)
.multilineTextAlignment(.leading)
.padding(.bottom, 10)
}
.padding(.horizontal, 20)
.frame(maxWidth: 640, alignment: .center)
}
.navigationBarTitle(product.title, displayMode: .inline)
.navigationBarHidden(true)
}
.edgesIgnoringSafeArea(.top)
}
}

I figured out the problem. I removed the navigationView and also the 2 lines
.navigationBarTitle(product.title, displayMode: .inline)
.navigationBarHidden(true)
As this was hiding the navigation buttons at the top of my view.

Related

Unable to navigate to a new view using navigation link in SwiftUI

is anybody able to see why I am unable to navigate to a new view I have created called "FavouritesView" using NavigationLink?
this is the code of the HomeView where I am navigating from
var body: some View {
VStack(spacing: 0) {
Text("test")
.font(.title.bold())
.frame(maxWidth: .infinity)
.overlay(alignment: .trailing) {
NavigationLink {
FavouritesView()
} label: {
Image(systemName: "doc.badge.gearshape")
.font(.title3)
.foregroundColor(.white)
.padding(.trailing, 20)
}
}
.padding(.bottom, 10)
all I'm doing is putting in a navigation link at the top right next to the title
. just want to tap and goto my other view. Probably something im missing here anyone know the fix ?
thanks
Wrap your VStack in a NavigationView like so:
var body: some View {
NavigationView {
VStack(spacing: 0) {
Text("test")
.font(.title.bold())
.frame(maxWidth: .infinity)
.overlay(alignment: .trailing) {
NavigationLink {
FavouritesView()
} label: {
Image(systemName: "doc.badge.gearshape")
.font(.title3)
.foregroundColor(.white)
.padding(.trailing, 20)
}
}
.padding(.bottom, 10)
And if you're using Xcode 14 beta, use the new NavigationStack for a more Advanced implementation. See this.

How to create design covering back button and top bar fully with cross button above it?

I am trying to create below design using swiftUI but not able to find proper approach.
I tried but my image is not covering back button but coming below to back button
Expected design
VStack(spacing: 16) {
VStack {
ZStack(alignment: .topTrailing) {
Image("defaultImage")
.resizable()
.frame( height: 200)
Button("Cancel", action: {
print("cancel")
})
.padding(12)
}
}
}
My Design :(
You might want to do a lot of try in SwiftUI to get a custom design right. gave it a quick try for you and added comments on the code so you can understand most of what i did.
this is the quick result i got (with a random background i got on internet)
import SwiftUI
struct FirstView: View{
var body: some View{
NavigationView {
VStack{
NavigationLink(destination: BackgroundImageNav()){
Text("Go to the view")
.font(.title)
}
}
}
}
}
struct BackgroundImageNav: View {
#Environment(\.presentationMode) var presentationMode
// remplacing the back button action, (only problem is that this disable the swipe back)
var body: some View {
ZStack {
// ZStack help you having your image behind the other views
VStack {
Image("defaultImage")
.resizable()
.frame(height: 180)
.edgesIgnoringSafeArea(.all)
Spacer()
// having a spacer that push the image on the top and ignoring the safe area
}
VStack(alignment:.leading){
HStack{
Button(action:{
presentationMode.wrappedValue.dismiss()
// back button action
}){
Image(systemName:"chevron.left")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30)
.foregroundColor(.white)
}
Spacer()
Rectangle()
.fill(Color.white)
.frame(width: 200, height: 80, alignment: .center)
Spacer()
Button(action:{
// do something
}){
Image(systemName: "xmark")
.resizable()
.frame(width: 24, height: 24)
.foregroundColor(.white)
}
}.padding()
Text("Title")
.bold()
.font(.title)
.foregroundColor(.black)
.background(Color.white)
.padding(24)
Spacer()
}
}.navigationBarHidden(true)
// removing the bar to customize the back button
}
}
struct backgroundImage_Previews: PreviewProvider {
static var previews: some View {
FirstView()
}
}

SwiftUI: How to get content aligned to top of screen, but keep back button

I'm learning SwiftUI (with Swift 5, targeting iOS 13.2)
Q) How do I get it so that my photo (and contents underneath) are aligned behind the notch area?
What I've got so far in the simulator:
As you can see, I've found out how to use an inline navigation bar style.
What I want
View Code:
import SwiftUI
struct DrinkDetail: View {
var drink: Drink
var body: some View {
List {
ZStack(alignment: .bottom) {
Image(drink.imageName)
.resizable()
.aspectRatio(contentMode: .fit)
Rectangle()
.frame(height: 80.0)
.opacity(0.75)
.blur(radius: 10)
HStack {
Text(drink.name)
.font(.largeTitle)
.foregroundColor(.white)
.padding(8)
Spacer()
}
}
.listRowInsets(EdgeInsets())
Text(drink.description)
.font(.body)
.foregroundColor(.primary)
.lineLimit(nil)
.padding(.bottom, 50.0)
.lineSpacing(12)
HStack {
Spacer()
Button(action: {}) {
Text("Order me")
}
.frame(width: 200.0, height: 50.0)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Spacer()
}
}
.edgesIgnoringSafeArea(.top)
.navigationBarTitle(Text(""), displayMode: .inline)
}
}
Looks like this simply isn't possible, despite the tutorial I watched showing it previously being possible.
Until further notice, this is the only way: https://stackoverflow.com/a/65523676/12299030

Unable to change background color of view in SwiftUI

I am trying to change background color main this view but unable to do it. I tried to put background(Color.green) at HStack, VSTack and even on ZStack but it did not work, not sure if i am putting at right place. By default it is taking phone or simulator color which is white but i want to apply custom background color
My Xcode version is 11.5
struct HomePageView: View {
#State var size = UIScreen.main.bounds.width / 1.6
var body: some View {
GeometryReader{_ in
VStack {
HStack {
ZStack{
// main home page components here....
NavigationView{
VStack {
AssignmentDaysView()
}.background(Color.lairBackgroundGray)
.frame(width: 100, height: 100, alignment: .top)
.navigationBarItems(leading: Button(action: {
self.size = 10
}, label: {
Image("menu")
.resizable()
.frame(width: 30, height: 30)
}).foregroundColor(.appHeadingColor), trailing:
Button(action: {
print("profile is pressed")
}) {
HStack {
NavigationLink(destination: ProfileView()) {
LinearGradient.lairHorizontalDark
.frame(width: 30, height: 30)
.mask(
Image(systemName: "person.crop.circle")
.resizable()
.scaledToFit()
)
}
}
}
).navigationBarTitle("Home", displayMode: .inline)
}
HStack{
menu(size: self.$size)
.cornerRadius(20)
.padding(.leading, -self.size)
.offset(x: -self.size)
Spacer()
}
Spacer()
}.animation(.spring()).background(Color.lairBackgroundGray)
Spacer()
}
}
}
}
}
struct HomePageView_Previews: PreviewProvider {
static var previews: some View {
HomePageView()
}
}
In your NavigationView you have a VStack. Instead you can use a ZStack and add a background below your VStack.
Try the following:
NavigationView {
ZStack {
Color.green // <- or any other Color/Gradient/View you want
.edgesIgnoringSafeArea(.all) // <- optionally, if you want to cover the whole screen
VStack {
Text("assignments")
}
.background(Color.gray)
.frame(width: 100, height: 100, alignment: .top)
}
}
Note: you use many stacks wrapped in a GeometryReader which you don't use. Consider simplifying your View by removing unnecessary stacks. Also you may not need a GeometryReader if you use UIScreen.main.bounds (however, GeometryReader is preferred in SwiftUI).
Try removing some layers: you can start with removing the top ones: GeometryReader, VStack, HStack...
Try the following:
Change the view background color especially safe area also
struct SignUpView: View {
var body: some View {
ZStack {
Color.blue //background color
}.edgesIgnoringSafeArea(.all)

SwiftUI view is in the middle instead of in the top

I'm trying to create a view in SwiftUI. In the preview, it looks like it should, but when run on my iPhone (or on the live preview) it looks like it is offset.
I tried to set the padding to -150, but then the TextField doesn't respond to touches.
VStack {
Text("Name:")
.padding(.bottom, 1)
TextField($name)
.padding(.horizontal, 25.0)
.textFieldStyle(.roundedBorder)
.frame(maxWidth: 500)
Text("Image:")
.padding(.top, 1)
Image(uiImage: image!)
.resizable(capInsets: EdgeInsets(), resizingMode: .stretch)
.scaledToFit()
.frame(width: 250, height: 250)
.clipShape(RoundedRectangle(cornerRadius: 10))
.padding(.top, 5)
Button(action: {
withAnimation {
self.showImagePicker = true
}
}) {
Text("Select Image")
.color(.init(red: 20/255, green: 146/255, blue: 81/255))
}
Button(action: {
let list = LSList( title: self.name,
image: self.image!,
id: 0)
list.add()
self.userData.listsData.append(list)
}) {
Text("Add List")
.color(.white)
.font(.system(size: 25))
.bold()
.padding(.horizontal, 7)
.frame(height: 35)
.background(Color.green)
.clipShape(RoundedRectangle(cornerRadius: 3))
}
Spacer()
} .navigationBarTitle(Text("Add List"))
The view in the preview:
The view on my iPhone:
I had the same issue, but found the the problem I had was in using navigationView multiple times.
I thought that we should have NavigationView in every view, but apparently, we should place navigationView only in the main view of the application, and all other views that we enter via navigationLink, automatically get the back option without the need to mention NavigationView again.
So check if you use navigationView more than once in your code.
Strangely, we can specify navigationBarTitle even in views that dont have the navigationView mentioned in them, this is because the navigationView is at the parent view.
Use "displayMode: .inline", to make the navigation area as minimal as possible, it will save you real-estate.
Another thing to do, is to use Spacer().
If you want all your items to be at the top, just put Spacer() as the last item in VStack, and it will push all items to the top.
See this example:
VStack {
// What you care about displaying
Text("Something to Show 1")
Text("Something to Show 2")
Text("Something to Show 3")
// This should be the last, put everything to the top
Spacer()
}
.navigationBarTitle(Text("The Title"), displayMode: .inline)
I had a similar issue, I wanted a VStack to align its content on the top of the screen, and was only using a NavigationView in the parent, but the VStack showed centered. What fixed it for me was using a Spacer(), like this:
VStack(alignment: .leading, spacing: 10){
HStack(alignment: .center, spacing: 5.0) {
...
}
Group{
...
}
Spacer() //<-- This solved my problem
}
Assuming that your VStack is wrapped in a NavigationView, this is the reason it is not rendering correctly in the simulator. The reason it shows fine in preview is that it is not displaying the navigation bar (which includes the back button as well) because the canvas doesn’t know this view might be pushed but in runtime the navigation bar is added while you’re also using an extra NavigationView as well.
To fix it unwrap the VStack from NavigationView and simply remove this NavigationView from the child view.
To make it visible correct with Navigation items in previews(even for child views) you need to wrap the View into the NavigationView { }, because the Canvas is an empty clean environment and it doesn't know that the View may be pushed into the NavigationView
To fix it on iPhone makes sure you are correctly pushing the child view. It should be NavigationButton(destination: AddList()) {}
Example of RowView implementation:
NavigationButton(destination: CarDetail(car: car)) {
HStack {
VStack(alignment: .leading) {
Text(car.name)
Text(car.isAvailable ? "Is Available" : "Out of stock")
.font(.subheadline)
.foregroundColor(.secondary)
}
}
}
ScrollView(.vertical){
VStack {
Text("Name:")
.padding(.bottom, 1)
TextField($name)
.padding(.horizontal, 25.0)
.textFieldStyle(.roundedBorder)
.frame(maxWidth: 500)
Text("Image:")
.padding(.top, 1)
Image(uiImage: image!)
.resizable(capInsets: EdgeInsets(), resizingMode: .stretch)
.scaledToFit()
.frame(width: 250, height: 250)
.clipShape(RoundedRectangle(cornerRadius: 10))
.padding(.top, 5)
Button(action: {
withAnimation {
self.showImagePicker = true
}
}) {
Text("Select Image")
.color(.init(red: 20/255, green: 146/255, blue: 81/255))
}
Button(action: {
let list = LSList( title: self.name,
image: self.image!,
id: 0)
list.add()
self.userData.listsData.append(list)
}) {
Text("Add List")
.color(.white)
.font(.system(size: 25))
.bold()
.padding(.horizontal, 7)
.frame(height: 35)
.background(Color.green)
.clipShape(RoundedRectangle(cornerRadius: 3))
}
Spacer()
} .navigationBarTitle(Text("Add List"))
}

Resources