alignment and constraint does not work in SwiftUI - iphone

I'm just trying to use the segment control which work on both -iPhone and iPad devices.
Using SwiftUI, below is the code and screenshot, this code does not work for iPad and different versions of iPhone devices.
struct ContentView: View {
#State private var favoriteColor = 0
var body: some View {
NavigationView {
HStack{
Picker("What is your favorite color?", selection: $favoriteColor) {
Text("Red").tag(0)
Text("Green").tag(1)
Text("Blue").tag(2)
}
.pickerStyle(.segmented)
.padding(.top,10)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView()
}
}
}
Attached screenshot
iPad
Not sure, how to align this for any iPhone or iPad devices

Your ipad view is not looking proper as you want Because you did not gave navigationViewStyle to your navigation View.
NavigationView {
HStack{
Picker("What is your favorite color?", selection: $favoriteColor) {
Text("Red").tag(0)
Text("Green").tag(1)
Text("Blue").tag(2)
}
.pickerStyle(.segmented)
.padding(.top,10)
}
}.navigationViewStyle(StackNavigationViewStyle())
Just add .navigationViewStyle(StackNavigationViewStyle()) at the end of your NavigationView.

As Namra Parmar said you need to set (override) the default navigation style of the iPad, because, by default, views are stacked up on iPhone, but they become columns on the iPad.
Here are some devices with different screen sizes: iPhone SE 1st gen (4.0inch), iPhone 13 Pro (6.06inch), iPhone 13 Pro Max (6.68inch), iPad pro (12.9inch), when you set the navigationViewStyle to "StackNavigationViewStyle()".

Related

SwiftUI navigation works on iOS but fails on macOS

I have an iOS SwiftUI app that works fine on iPhone and iPad, but when compiled for native macOS the navigation links are disabled. Code is below. Briefly, the FirstView is a NavigationView containing a List of NavigationLinks. These work, and link to a DetailView that contains a next level of NavigationLinks presented as Images.
On iOS, these images are active blue that when clicked, go to a FinalView.
On macOS, these images are inactive: Presented as gray, and don't have any click-ability.
Why do these appear differently on the two OS's? How to fix the macOS version so that it navigates? Thanks in advance
import SwiftUI
struct TNode { // simple data struct that just carries name and ID
public let id = UUID()
public let name : String
init( _ name:String) {
self.name = name
}
}
// starting view
struct FirstView: View {
init () {
// provide some sample data
nodes = [TNode("node 1"), TNode("node 2")]
}
#State private var nodes : [TNode]
var body: some View {
NavigationView {
List {
ForEach(nodes, id:\.id) { (node) in
// where to go when selected
NavigationLink(destination:
DetailView(displayNode: node)
){ // display names for selection in the sidebar
VStack {
Text(node.name)
}
}
}
}
}
}
}
struct DetailView: View {
let displayNode : TNode
var body: some View {
VStack(alignment: .leading) {
Text(displayNode.name)
HStack{
// this is what doesn't work on macOS
NavigationLink(destination: FinalView()) {
Image(systemName:"figure.stand.line.dotted.figure.stand")
}
NavigationLink(destination: FinalView()) {
Image(systemName:"square.and.pencil")
}
}
}
}
}
struct FinalView : View {
var body : some View {
Text("Got to final view OK")
}
}
Behavior on macOS:
Xcode 13.4.1, macOS Monterey 12.4
Embed the VStack of the DetailView in a NavigationView. Remember that iOS is different than macOS.
In iOS you didn't need to wrap the child View of in a NavigationView because it's a child. With macOS this a standalone View.
Remove Stack in Navigation link :
){ // display names for selection in the sidebar
// Remove VStack VStack {
Text(node.name)
// }
}

SwiftUI NavigationView Stuck after a Few Steps

I am walking my first steps with SwiftUI as I'm thinking about migrating my existing UIKit-based iOS app. It makes extensive use of split views. Ideally, there will be something like the iOS Mail app with a master/detail view as well as an additional (leftmost) column for selecting content, account, etc.
For now, I am stuck on some basic issues such as this one: I created a short list of navigation links and a default content to be shown when the app initially opens the detail view. This works as expected when navigating back and forth in "stacked" mode, i.e. on iPhone in portrait orientation. Changing to multiple-column view, e.g. iPhone max in landscape, the primary column is stuck after a few steps. In landscape view, I have to manually hide it by clicking on the detail, and in portrait view the detail view does no longer show at all.
import SwiftUI
#main
struct MyApp: App {
var body: some Scene {
WindowGroup {
NavigationView {
List {
NavigationLink(destination: destination1) {
Text("Hello, World 1!")
}
NavigationLink(destination: destination2) {
Text("Hello, World 2!")
}
.navigationTitle("Primary")
}
Text("This is the default content shown when the navigation view is created.")
}
}
}
var destination1: some View {
Text("Destination 1 text.")
.navigationTitle("secondary 1")
}
var destination2: some View {
Text("Destination 2 text.")
.navigationTitle("secondary 2")
}
}

Layout multiple SwiftUI previews horizontally (or in grid) instead of vertically?

When rendering multiple SwiftUI previous, they always render in a vertical stack. I would like to lay them out horizontally or ideally on a grid., because I have more horizontal space on my screen.
It's unproductive to have to keep scrolling up-and-down between multiple the previews, especially when you have more than two.
Anyone know a work around, or if it's possible?
Update:
E.g. As you see in the screen shot, I want to those two previews side by side horizontally.
Xcode Version 12.0 beta (12A6159)
You can achieve it like this. This way it doesn't show iPhone borders but views render it as how it will look on iPhone 11 Pro screen.
struct SidebarView_Previews: PreviewProvider {
static var previews: some View {
HStack {
//... All your views ...
}.previewLayout(.fixed(width: 375 * 2, height: 812))
}
}
Just replace the preview Group by an HStack, this way:
struct SidebarView_Previews: PreviewProvider {
static var previews: some View {
Group {
//... All your views ...
}
}
}
to:
struct SidebarView_Previews: PreviewProvider {
static var previews: some View {
HStack(spacing: 20) {
//... All your views ...
}
}
}

Swiftui [BUG] NavigationView and List not showing on iPad simulator only

Blank page on all kinds of iPad simulator
Go to Apple developer website to download tutorials project below:
https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation
Run this on any iPad simulator, you will just get a blank page, but the code works fine on simulator of Mac/iPhone and my real iPhone device.
This is definitely a bug, and I've reported to Apple, I am posting here just want ppl like me who said this issue, pls don't waste your time on reset simulator, checking your code, restart your laptop, wait until apple to fix this.
Screenshot
Sample code from Apple SwiftUI tutorials project:
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE", "iPhone XS Max"], id: \.self) { deviceName in
LandmarkList()
.previewDevice(PreviewDevice(rawValue: deviceName))
.previewDisplayName(deviceName)
}
}
}
It's actually working just fine. By default, on iPad, the navigationStyle of a NavigationView means that you are seeing the detail view with a collapsed master view. Try rotating device or simulator and you will then see your master list. Selecting an item will push that onto the detail view. Or, swipe right from the left edge and your list will appear.
Don't like this behavior? You can set your navigation view's navigationStyle to StackNavigationViewStyle(). It will only show a single view on top at any given time.
I can't currently find an option to always show the master view as that is currently how my app is configured using a UISplitViewController. It is likely a temporary situation.
According to answer of #Procrastin8, I am here to show the example code, you just need to add one line of code .navigationViewStyle(StackNavigationViewStyle()
import SwiftUI
struct LandmarkList: View {
var body: some View {
NavigationView {
List(landmarkData) { landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
.navigationBarTitle(Text("Landmarks"))
}.navigationViewStyle(StackNavigationViewStyle())
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE", "iPhone XS Max"], id: \.self) { deviceName in
LandmarkList()
.previewDevice(PreviewDevice(rawValue: deviceName))
.previewDisplayName(deviceName)
}
}
}
Screenshot
When I first saw my app on the iPad I was also put off. But then I realized it makes sense not to waste all the screen on a List, so I show the first item in a detail view by default:
var body: some View {
NavigationView {
// Main view (by default shows on iPhone but not on iPad)
VStack{
List {
ForEach(viewModel.arPictures, id: \.date) { potd in
NavigationLink(destination: POTDDetailView(potd: potd)) {
Text(potd.title ?? "")
}
}
}
}.navigationBarTitle(Text("Last 8 days pictures"), displayMode: .inline)
// Detail view (by default shows on iPad but not on iPhone)
if (!viewModel.arPictures.isEmpty){
POTDDetailView(potd: viewModel.arPictures[0])
}
}
}

SwiftUI Navigation on iPad - How to show master list

My app has simple navigation needs
List View (parent objects)
List View (child objects)
Detail View (child object)
I have this setup and working on iPhone, but when I run the app on iPad in portrait mode the master list is always hidden.
I'm using .isDetailLink(false) on the navigation link from the first list to the second, so both lists always stay in the master column. In iPad landscape everything works as expected but in portrait the detail view fills the screen. I can swipe in from the left side of the screen to show the list but I'd like to provide more clarity to the user.
I'd like to show or add the back button to show the master/list side (sort of like the Apple Notes app). On the iPhone I get the back button by default but on iPad in portrait mode there is nothing in its place.
This is what I see on iPhone
But this is what I see on iPad
Parent list
struct ParentList: View {
let firstList = ["Sample data 01", "Sample data 02", "Sample data 03", "Sample data 04", "Sample data 05"]
var body: some View {
NavigationView {
List{
ForEach(firstList, id: \.self) { item in
NavigationLink(destination: ChildList()){
Text(item)
}
.isDetailLink(false)
}
}
}
}
}
Child list
struct ChildList: View {
let secondList = ["More Sample data 01", "More Sample data 02", "More Sample data 03", "More Sample data 04", "More Sample data 05"]
var body: some View {
List{
ForEach(secondList, id: \.self) { item in
NavigationLink(destination: ChildDetail()){
Text(item)
}
}
}
}
}
Child detail
struct ChildDetail: View {
var body: some View {
Text("Child detail view")
}
}
Update: As of Oct 17, 2019 I have not found a way to get this to work. I decided to use .navigationViewStyle(StackNavigationViewStyle()) for the time being. Interestingly, this needs to go outside of the navigation view like a normal modifier, not inside it with the navigation title.
In portrait the default split view does not work. This may be fixed in future but it appears the current options are:
(a) change the navigation view style of your first list to .navigationViewStyle(StackNavigationViewStyle()) so the navigation will work like on iPhone and push each view.
(b) leave the style to default and only support landscape for iPad
(c) implement a UIKit split view controller
There also is a quite hacky workaround (see https://stackoverflow.com/a/57215664/3187762)
By adding .padding() to the NavigationView it seems to achieve the behaviour of always display the Master.
NavigationView {
MyMasterView()
DetailsView()
}.navigationViewStyle(DoubleColumnNavigationViewStyle())
.padding()
Not sure if it is intended though. Might break in the future (works using Xcode 11.0, in simulator on iOS 13.0 and device with 13.1.2).
You should not rely on it. This comment seems to be the better answer: https://stackoverflow.com/a/57919024/3187762
in iOS 13.4, a "back to master view" button has been added to the iPad layout. From the release notes:
When using a NavigationView with multiple columns, the navigation bar now shows a control to toggle the columns. (49074511)
For example:
struct MyNavView: View {
var body: some View {
NavigationView {
NavigationLink(
destination: Text("navigated"),
label: {Text("Go somwhere")}
)
.navigationBarTitle("Pick Item")
}
}
}
Has the following result:
Look this solution here
I hope this help
For my project I'm using this extension.
They will always use StackNavigationViewStyle for iPhone, iPad in a vertical orientation, and if you provide forceStackedStyle: true.
Otherwise DoubleColumnNavigationViewStyle will be used.
var body: some View {
NavigationView {
Text("Hello world")
}
.resolveNavigationViewStyle(forceStackedStyle: false)
}
extension View {
func resolveNavigationViewStyle(forceStackedStyle: Bool) -> some View {
if forceStackedStyle || UIDevice.current.userInterfaceIdiom == .phone {
return self.navigationViewStyle(StackNavigationViewStyle())
.eraseToAnyView()
} else {
return GeometryReader { p in
if p.size.height > p.size.width { self.navigationViewStyle(StackNavigationViewStyle())
} else {
self.navigationViewStyle(DoubleColumnNavigationViewStyle())
}
}
.eraseToAnyView()
}
}
}