when I open the app on ipad simulator the design is broken - swift

When I run the app on the iPad, the design does not appear on the screen. When you click on Home in the top left navigation bar, the design comes up, but it is half loaded. When I delete the NavigationView, the normal design appears but is not clickable.
struct MainView: View {
#EnvironmentObject var store: BlogPostsStore
#Environment(\.colorScheme) var colorScheme
var featuredPosts: [BlogPost] {
return store.blogPosts.filter {$0.featured == true}
}
var body: some View {
NavigationView {
ScrollView {
// featured article
if featuredPosts.count > 0 {
VStack {
HStack {
Text("Featured posts")
.font(.title.bold())
Spacer()
}
LazyVStack {
ForEach(featuredPosts) {post in
NavigationLink(destination: BlogPostView(blogPost: post)) {
BlogPostCardMain(blogPost: post)
}
}
}
}
.padding(.horizontal, 15)
.padding(.vertical, 30)
}
// latest articles
VStack {
HStack {
Text("Latest posts")
.font(.title.bold())
Spacer()
}
.padding(.horizontal, 15)
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack(spacing: 15) {
if store.blogPosts.count >= 3 {
ForEach(store.blogPosts[0...2]) {post in
NavigationLink(destination: BlogPostView(blogPost: post)) {
BlogPostCardMain(blogPost: post)
}
}
} else {
ForEach(store.blogPosts[0..<store.blogPosts.count]) {post in
NavigationLink(destination: BlogPostView(blogPost: post)) {
BlogPostCardMain(blogPost: post)
}
}
}
}
.padding(.leading, 15)
.padding(.trailing, 30)
}
.frame(height: 420)
Spacer()
}
.padding(.bottom, 40)
}
.navigationBarTitle("Home")
.navigationBarItems(
trailing: Button(action: {store.refreshView()}) { Image(systemName: "arrow.clockwise.circle.fill")
.resizable()
.frame(width: 30, height: 30)
})
}
}
}
enter image description here
enter image description here

This is down to how NavigationView works on iPads (and also larger iPhones in landscape).
The first view given to NavigationView acts as the collapsible left hand navigation, which is a fixed width. Any NavigationLink destinations in that view will open in the main, “detail” view that takes up the full screen.
You can specify a second view underneath the first one to provide a ‘default’ view to display in the main screen:
NavigationView {
// the sidebar view
ScrollView {
// etc.
}
// the default view
Text("Default view")
}
You could also add a third view, which will automatically give your iPad a three-column view similar to that used by Mail, etc. if you wanted to.
Another option is to force the NavigationView to work exactly the same way as it does for an iPhone in portrait mode, by adding a .navigationViewStyle argument:
NavigationView {
// contents as before
}
.navigationViewStyle(.stack)
While that will give you an iPhone-like experience on the iPad, it doesn’t really take full use of the larger screen space without careful design work. For that reason, it’s usually a good idea to invest some time in coming up with an app design that is tailored to the default iPad style of navigation view.

Related

Swift UI Navigation View not switching the whole screen

I want to create a simple NavigationView. But with code outside of it. Like this:
struct TestView: View {
var body: some View {
VStack{
RoundedRectangle(cornerRadius: 10)
.frame(width: 100, height: 100)
NavigationView {
VStack{
NavigationLink {
Text("HEllo")
} label: {
Text("Click me")
}
.navigationViewStyle(.columns)
}
.navigationTitle("A Title")
}
}
}
}
I do that so the navigation Title is below the item outside the NavigationView.
This code gives me this:
Image because I am not allowed to insert images yet.
When I click on the NavigationLink though I see this:
The Image
As you see the RoundedRectangle still is viewable at top of the screen. How can I fix that, so that the Rectangle disappears and the Destination is viewable in full screen?
Set navigation view first, You have to put everything inside the navigation view.
NavigationView { // Here
VStack{
RoundedRectangle(cornerRadius: 10)
.frame(width: 100, height: 100)
VStack{ // Remove from above
The RoundedRectangle is still visible because it is outside of the NavigationView, only the content of the NavigationView will move with the NavigationLink
Something you could do is to use the toolbar of the NavigationView to place items on the top of the screen
struct TestView: View {
var body: some View {
NavigationView {
NavigationLink {
Text("HEllo")
} label: {
Text("Click me")
}
.navigationViewStyle(.columns)
.navigationTitle("A Title")
.toolbar {
ToolbarItem {
RoundedRectangle(cornerRadius: 10)
.frame(width: 100, height: 100)
}
}
}
}
}

Add Padding to TabView Page Indicator

I have a view that is a TabView with the style PageTabViewStyle(indexDisplayMode: .always which looks great for my use case however the page indicator is bumping right up to the safe area near the bottom of the screen and it looks bad. I'd like to move the page indicator up to some n value. here's a sample of my view to reproducing it. If this view were built on any device without a Home Button, it will ride on top of the home indicator line.
var body: some View {
ZStack {
TabView(selection: $homeVM.selectedPageIndex) {
// Any number of views here.
}
.frame(width: UIScreen.main.bounds.width)
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .never))
}.edgesIgnoringSafeArea(.all)
}
I attempted to add the padding to the ZStack, which does work but then my TabView is cut off on the bottom, which means my cells disappear prematurely.
Here's an image for what I'm trying to fix. Notice the page indicator sits on the home bar indicator. I need the indicators pushed up, without pushing up the background ScrollView
Update #1
This view is being presented by a base view that I use to handle my navigation stack. The view is as follows. The important thing to note here is the .ignoresSafeArea() that I have on this view. I did that because it's a containing view for my eventual TabView to be presented from. Interestingly if I remove this modifier the indicators move up to a more manageable position, but then my form becomes clipped at the top and bottom of the device when scrolling, and that's not ideal.
struct BaseLaunchView: View {
#StateObject var baseNavVM = BaseLaunchViewModel()
#State var shouldLogin = false
#State var shouldRegister = false
var body: some View {
VStack {
switch baseNavVM.loggedIn {
case true:
HomeView()
default:
NavigationView {
VStack{
Spacer()
VStack(spacing: 30) {
VStack {
Text("Stello")
.font(Fonts.title)
Text("Life Groups")
.font(Fonts.body)
}
StelloDivider()
Text("Connect with like minded people, to fellowship and find your home.")
.font(Fonts.subheading)
.multilineTextAlignment(.center)
}
Spacer()
NavigationLink(destination: RegisterOptionsView(isLoggingIn: true), isActive: $shouldLogin) {
Button(action: {
shouldLogin.toggle()
}, label: {
Text("Login")
.font(Fonts.button)
}).buttonStyle(StelloFillButtonStyle())
}
NavigationLink(destination: RegisterOptionsView(isLoggingIn: false), isActive: $shouldRegister) {
Button(action: {
shouldRegister.toggle()
}, label: {
Text("Register")
.font(Fonts.button)
}).buttonStyle(StelloHollowButtonStyle())
}
}
}.accentColor(.black)
}
}
.padding()
.environmentObject(baseNavVM)
.ignoresSafeArea()
}
}

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

SwiftUI NavigationView trying to pop to missing destination (Monoceros?)

I'm using Xcode 12 with deployment for iOS 14.0.
My home screen has a NavigationView
Within the NavigationView there is a TabView (with 4 tabs)
Within each tab are subviews that have buttons and NavigationLinks
The navigation on the app is functioning correctly (when I click a NavigationLink on one of the subviews, it navigates to the correct view and when I click the back button, it dismisses the view.) However, when I click the back button, the console prints the following error:
Trying to pop to a missing destination at /Library/Caches/com.apple.xbs/Sources/Monoceros/Monoceros-103/Shared/NavigationBridge_PhoneTV.swift:337
Aside from the error log, the app is functioning fine, so I'm planning to just ignore the error for now... but I'm wondering what it means? I don't have anything within my code named "Monoceros". I'm guessing it has something to do with the TabView being a subview of the NavigationView?
EDIT:
Several months later, this issue still persists. Here is reproducible code. Open the ContentView(), on the FirstScreen() click on the NavigationLink, then click the back button. It will print out Monoceros lol
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
FirstScreen()
.tabItem {
Text("One")
Image(systemName: "house.fill")
}
Text("Second Screen")
.tabItem {
Text("Two")
Image(systemName: "heart.fill")
}
}
}
}
}
struct FirstScreen: View {
var body: some View {
NavigationLink("Click here", destination: Text("Final Screen"))
// Click the back button on FinalScreen prints:
//Trying to pop to a missing destination at /Library/Caches/com.apple.xbs/Sources/Monoceros_Sim/Monoceros-120/Shared/NavigationBridge_PhoneTV.swift:341
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Unfortunately this is an active issue with a TabView placed inside NavigationView.
The error would not manifest itself if you placed your NavigationView inside the TabView, but this of course would lead to the tabs being displayed from within your Final Screen, which you are probably trying to avoid.
                                      
There is currently no work-around for this, and as of to date we need to wait for Apple to properly implement the corresponding .navigationBarHidden() of TabViews as well.
Problems and unexpected behaviours have been reported when embedding a TabView into a NavigationView, however if you have tested your app thoroughly and found no particular problems, it is safe to say that you can stick to this method.
Alternatively you will have to build a TabView component manually, like below:
import SwiftUI
enum Tab {
case house, heart
}
struct TabView: View {
#Binding var tabIdx: Tab
var body: some View {
HStack {
Group {
Spacer()
Button (action: {
self.tabIdx = .house
}) {
VStack{
Image(systemName: "house.fill")
Text("House")
.font(.system(size: 10))
}
}
.foregroundColor(self.tabIdx == .house ? .blue : .secondary)
Spacer()
Button (action: {
self.tabIdx = .heart
}) {
VStack{
Image(systemName: "heart.fill")
Text("Heart")
.font(.system(size: 10))
}
}
.foregroundColor(self.tabIdx == .heart ? .blue : .secondary)
Spacer()
}
}
.padding(.bottom, 30)
.padding(.top, 10)
.background(Color(red: 0.1, green: 0.1, blue: 0.1))
.font(.system(size: 30))
.frame(height: 80)
}
}
struct FirstScreen: View {
var body: some View {
NavigationLink("Click here", destination: Text("Final Screen"))
.font(.system(size:20))
}
}
struct ContentView: View {
#State var tabIdx: Tab = .house
var body: some View {
NavigationView {
VStack(spacing: 20) {
Spacer()
if tabIdx == .house {
FirstScreen()
} else if tabIdx == .heart {
Text("Second Screen")
}
Spacer(minLength: 0)
TabView(tabIdx: self.$tabIdx)
}
.ignoresSafeArea()
}
}
}
The above bug is well detailed in this blog post, which you could consult for further reference and more examples.

Problem with SwiftUI: Vertical ScrollView with Button

I'm quite new to programming so please excuse any dumb questions. I'm trying to make a ScrollView with the content being buttons. Although the button prints to console, when shown in the simulator the button displays as a large blue rectangle rather than displaying the image I would like it to.
Code Regarding ScrollView:
struct ContentView: View {
var body: some View {
[Simulator Display][1]
VStack {
Image("logo")
.resizable()
.aspectRatio(contentMode: .fit)
.padding(.leading, 50)
.padding(.trailing, 50)
.padding(.top, 20)
.padding(.bottom, -20)
Spacer()
ScrollView {
VStack(spacing: 20) {
Button(action: {
//ToDo
print("Executed")
}) {
Image("Logo")
}
}
}
}
}
}
Simulator Display:
Image(Placeholder for now) I want to be displayed:
So I tried it an yeah it was very weird. Anyway, here is an example of how you can include the image. Just take the portion of the Button and paste it
struct ContentView: View {
var body: some View {
ZStack {
Button(action: {
print("button pressed")
}) {
Image("image")
.renderingMode(.original)
}
}
}
}