TabbedView using SwiftUI in Xcode11Beta (11M336w) - swift

I am following along with the session from WWDC2019 here :
https://developer.apple.com/videos/play/wwdc2019/216/
I have the following code working for creating a TabbedView using SwiftUI :
//Section1 | ContentView (mine)---------------------------
import SwiftUI
struct ContentView : View {
var body: some View {
NavigationView {
TabbedView(selection: .constant(1)) {
PlaceForm().tabItemLabel(Text("Tab1")).tag(1)
FavoritesForm().tabItemLabel(Text("Tab2")).tag(2)
}
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
//---------------------------
The above produces the following tabbed view :
However, in the WWDC2019 session, the following code is used :
//Section2 | ContentView (Apple's)---------------------------
import SwiftUI
struct ContentView : View {
var body: some View {
NavigationView {
TabbedView(selection: .constant(1)) {
PlaceForm().tabItemLabel {
Image(systemName: "square.and.pencil")
Text("Tab1")
}
FavoritesForm().tabItemLabel {
Image(systemName: "clock.fill")
Text("Tab2")
}
}
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
//---------------------------
However, on Xcode11Beta, this results in the following compiler error being thrown by Xcode11Beta
Cannot convert value of type 'TabbedView<Int,
TupleView<(_ModifiedContent<PlaceForm, _TraitWritingModifier<AnyView?>>,
_ModifiedContent<FavoritesForm, _TraitWritingModifier<AnyView?>>)>>' to
closure result type '_'
as seen in the following screenshots
and
//---------------------------
What is the reason that the code demonstrated in the WWDC2019 slides don't result in the images showing up in the tabs of the tabbed view as should be expected if the information in the WWDC2019 presentation is correct?
Also, with the code in section1, switching tabs to tab2 shows a blank view as described in the following question :
SwiftUI TabbedView only shows first tab's content
Please note that the contents of PlaceForm and FavoritesForm are as reproduced below
//Section3 | PlaceForm---------------------------
import SwiftUI
struct PlaceForm : View {
var body: some View {
List {
VStack {
MapView()
.edgesIgnoringSafeArea(.top)
.frame(height: 300)
CircleImage()
.offset(y: -130)
.padding(.bottom, -130)
VStack {
VStack {
Text("Turtle Rock")
.font(.title)
.color(.black)
}
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding()
}
}.listStyle(.grouped)
}
}
#if DEBUG
struct PlaceForm_Previews : PreviewProvider {
static var previews: some View {
PlaceForm()
}
}
#endif
//Section4 | FavoritesForm---------------------------
import SwiftUI
struct FavoritesForm : View {
var body: some View {
List {
VStack {
MapView()
.edgesIgnoringSafeArea(.top)
.frame(height: 300)
CircleImage()
.offset(y: -130)
.padding(.bottom, -130)
VStack {
VStack {
Text("Ninja Rock")
.font(.title)
.color(.black)
}
HStack {
Text("Joshua Tree National Park")
.font(.subheadline)
Spacer()
Text("California")
.font(.subheadline)
}
}
.padding()
}
}.listStyle(.grouped)
}
}
#if DEBUG
struct FavoritesForm_Previews : PreviewProvider {
static var previews: some View {
FavoritesForm()
}
}
#endif

This issue was fixed with Xcode 11 beta 3. From iOS & iPadOS 13 Beta 3 Release Notes:
The tabItemLabel(:) modifier — now named tabItem(:) — now accepts
#ViewBuilder closures. (51502668)
Example:
myView()
.tabItem {
Image(systemName: "circle")
Text("Tab1")
}

I had success in Beta 2 by wrapping the 2 controls inside tabItemLabel with a VStack:
.tabItemLabel(VStack {
Image(systemName: "list.bullet")
Text("Foo").font(.title)
})

After some playing around, it looks like tabbed views don't accept system images yet. This code compiled for me. I'm running Xcode 11.0 beta (11M336w) on Catalina 10.15 Beta (19A487m).
struct TabView : View {
var body: some View {
TabbedView {
HomeFeedUIV().tabItemLabel(Image(systemName: "house")) // doesn't work
DatabaseHomeUIV().tabItemLabel(Image("database.unselected")) // works
NewPostUIV().tabItemLabel(Image(systemName: "square.and.pencil")) // doesn't work
}
}
}
I tried using a VStack for the tabItemLabels (Image and Text) but the debugger said tabItemLabels don't accept VStacks, only Images and text. I have yet to find out how to make text and and image appear, it seems to only accept one or the other. I've tried using parenthesis, brackets, curly braces, VStacks, none of them work. Looks like it's one or the other for now.

Related

LazyVGrid code behaves differently in different Xcode versions?

I was just watching Standord's CS193p (2021 editions)
The instructor shows this as an example of LazyVGrid:
As you see the spacing is equal in every direction.
Now here is how I see it with the exact same code in Xcode 14.2 (it's the same with 9 cards too):
I double checked and the code is exactly the same for both of us!
import SwiftUI
struct ContentView: View {
var emojis = ["✈️", "🚀", "🚑", "🚕", "🚁", "🚜", "🚂", "🛻", "🏍️"]
#State var emojiCount = 8
var body: some View {
VStack {
LazyVGrid(columns: [GridItem(),GridItem(),GridItem(),GridItem()]) {
ForEach(emojis[0..<emojiCount], id: \.self) { emoji in
CardView(content: emoji).aspectRatio(2/3, contentMode: .fit)
}
}
.foregroundColor(.red)
Spacer()
HStack {
remove
Spacer()
add
}
.font(.largeTitle)
.padding(.horizontal)
}
.padding(.horizontal)
}
var remove: some View {
Button {
if emojiCount > 1 {
emojiCount -= 1
}
} label: {
Image(systemName: "minus.circle")
}
}
var add: some View {
Button {
if emojiCount < emojis.count {
emojiCount += 1
}
} label: {
Image(systemName: "plus.circle")
}
}
}
struct CardView: View {
var content: String
#State var isFaceUp: Bool = true
var body: some View {
ZStack {
let shape = RoundedRectangle(cornerRadius: 25)
if isFaceUp {
shape.fill(.white)
shape.stroke(lineWidth: 3)
Text(content).font(.largeTitle)
} else {
shape.fill(.red)
}
}
.onTapGesture {
isFaceUp = !isFaceUp
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
ContentView()
.preferredColorScheme(.dark)
}
}
How is that possible? if Apple just changes the behavior like that, what happens to old apps when running in newer devices?
Also, how can I set the vertical spacing to be exactly the same as horizonal spacing? (I am aware I can set the vertical spacing like this: LazyVGrid(columns:..., spacing: 10), but that is a fixed amount and not always equal to horizontal spacing depending on the cols)
Timed link to the video on Youtube
Edit:
Funny enough, removing the Text() inside card or adding .padding() to it fixes the issue, but I still don't understand why, it is more confusing when you watch the video:
Link to Video

SwiftUI Tutorial: Scrumdigger Spacer() issue

I have been working through the SwiftUI Scrumdigger tutorial (https://developer.apple.com/tutorials/app-dev-training/getting-started-with-scrumdinger) and have reached Step 7 of "Creating a Card View". Here is where my experience deviates from what is presented by the tutorial.
Here is the code both I and the tutorial are using:
import SwiftUI
struct CardView: View {
let scrum: DailyScrum
var body: some View {
VStack(alignment: .leading) {
Text(scrum.title)
.font(.headline)
Spacer()
HStack {
Label("\(scrum.attendees.count)", systemImage: "person.3")
}
}
}
}
struct CardView_Previews: PreviewProvider {
static var scrum = DailyScrum.sampleData[0]
static var previews: some View {
CardView(scrum: scrum)
.background(scrum.theme.mainColor)
.previewLayout(.fixed(width: 400, height: 60))
}
}
Here is what I see:
And here is what the tutorial displays:
I have tried moving the Spacer() from line 9 to line 13 but the issue is the same.
Can reproduce without the reliance on the external Scrum data using this:
import SwiftUI
struct CardView: View {
//let scrum: DailyScrum
var body: some View {
VStack(alignment: .leading) {
Text("Title")
.font(.headline)
Spacer()
HStack {
Label("3", systemImage: "person.3")
}
}
}
}
struct CardView_Previews: PreviewProvider {
//static var scrum = DailyScrum.sampleData[0]
static var previews: some View {
CardView()
.previewLayout(.fixed(width: 400, height: 60))
}
}
Can anyone advise as to what might be going wrong here?

Taking Top Space When Adding Tab Bar in SwiftUI

I am integrating Side Menu in my SwiftUI app. The side menu is working fine. The problem I am getting is I have a tab bar at the bottom, and when I open my side menu screen, it is taking some space from the top and I am not getting why it is getting that space. This is what I am getting:
And when I open Debug View Hierarchy, it is showing me this:
This is my code for my home screen:
struct HomeView: View {
#State var menuOpen: Bool = false
var body: some View {
Zstack {
ZStack {
HStack {
if !self.menuOpen {
Button {
print("side menu tapped")
self.menuOpen.toggle()
} label: {
Image("sideMenuButton")
.resizable()
.frame(width: 24, height: 24)
}.padding()
}
Spacer()
}
Text("Home")
.font(.custom(Poppins.semiBold.rawValue, size: 17))
.foregroundColor(Color(ColorName.appBlue.rawValue))
}
ZStack {
SideMenu(width: 300,
isOpen: self.menuOpen,
menuClose: self.openMenu)
}
}
}.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
func openMenu() {
self.menuOpen.toggle()
}
}
This is working fine when I use it without tab bar. Without tab bar it looks like this:
My code for tab bar controller is:
struct TabBarControllerView: View {
#State private var tabSelection = 0
var body: some View {
TabView(selection: $tabSelection) {
HomeView()
.tabItem {
Label("Home", image: tabSelection == 0 ? ImageName.home.rawValue : ImageName.silverHome.rawValue)
}
.tag(0)
MyAccountView()
.tabItem {
Label("Claims", image: tabSelection == 1 ? ImageName.claims.rawValue : ImageName.silverClaims.rawValue)
}
.tag(1)
}.accentColor(Color(ColorName.appBlue.rawValue))
}
}
struct TabBarControllerView_Previews: PreviewProvider {
static var previews: some View {
TabBarControllerView()
}
}
Does anyone knows why is it getting the top space? I tried .ignoresSafeArea() and also gave padding in negative, it went to top but the side menu did not tapping because it is getting under that space.
I am been stuck in this for 2 days, any help will be appreciated.
TabView comes with Navigation Bar up top. There is a simple solution by adding .navigationBarHidden(true).
See this post: SwiftUI how to hide navigation bar with TabView
Note: Also in the future give a proper minimum amount of code to reproduce the behavior. Your current code given relies on other components and isn't runnable by itself on a fresh project.
Update:
I created a minimum project to test this and this code works fine with me:
import SwiftUI
#main
struct testApp: App {
var body: some Scene {
WindowGroup {
TabBarView()
}
}
}
struct TabBarView: View {
#State private var tabSelection = 0
var body: some View {
TabView(selection: $tabSelection) {
HomeView()
.tabItem {
Label("Home", systemImage: "house")
}
.tag(0)
}
}
}
struct HomeView: View {
var body: some View {
ZStack {
Rectangle().foregroundColor(.green)
VStack {
HStack {
Spacer()
Button {
print("side menu tapped")
} label: {
Image(systemName: "pencil")
.resizable()
.frame(width: 24, height: 24)
}.padding()
Spacer()
}
Spacer()
}
}
}
}
Given that this code works fine and the issue is not here, minimum working code sample is needed from OP.

In SwiftUI, how can I put the navigation bar in the inner view?

In SwiftUI I want to implement the following view. But I have no idea how I can put the navigation bar in the white view inside. Because it is placed on top of the purple view by default.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
Color.purple
WhiteView() // the white view
.padding(.top, 30)
.padding()
}
.edgesIgnoringSafeArea(.all)
}
}
import SwiftUI
struct WhiteView: View {
var body: some View {
Color.white
.cornerRadius (12)
}
}
struct WhiteView_Previews: PreviewProvider {
static var previews: some View {
WhiteView()
}
}
Here is possible approach - use NavigationView over color view, so it takes frame of parent view but not full screen
Tested with Xcode 12.4 / iOS 14.4
struct WhiteView: View {
var body: some View {
Color.white
.overlay(NavigationView {
NavigationLink("Test", destination: Text("Details"))
})
.cornerRadius (12)
}
}
I took your code, stuck it in a NavigationView, added a .navigationTitle, .toolbar and ToolBarItem and this is the View I got:
Code:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
ZStack {
Color.purple
WhiteView() // the white view
.padding(.top, 30)
.padding()
}
.edgesIgnoringSafeArea(.all)
.navigationTitle("Your Friends")
.toolbar {
ToolbarItem {
Text("Right Button")
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct WhiteView: View {
var body: some View {
Color.white
.cornerRadius (12)
}
}
What, exactly is your question/problem? Everything is in the white area.

SwiftUI can't create navigationview

I'm following through some swiftUI tutorial and I couldn't figure out what this meant.
This was the very first step, and I haven't done anything other than adding the NavigationView. How do I resolve this?
That's just container, you need some content inside, If you are just trying something out try following:
var body: some View {
NavigationView {
Text("Testing")
}
}
You cannot have an empty NavigationView. Add something inside.
struct ContentView: View {
var body: some View {
NavigationView {
Text("Text here")
}
}
}
FIRST: Add new SwiftUI-View (Name: MapView.swift without code-changing )
SECOND: Add new SwiftUI-View (Name: SecondView.swift)
THEN Change ContentView and SecondView:
a) ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
MapView() // on upper Screen will appear: "Hello World"
NavigationView {
NavigationLink(destination: SecondView()) {
VStack {
Text("click here")
.fontWeight(.heavy)
.font(.largeTitle)
.padding()
Text("go to screen II")
}
}
} //End of NavigationView
}// End of VStack
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
VStack {
ContentView()
}
}
}
b) SecondView.swift
import SwiftUI
struct SecondView: View {
var body: some View {
VStack {
Text("Screen II")
.fontWeight(.heavy)
.foregroundColor(.blue)
.font(.largeTitle)
.padding()
Text("you changed it")
Text("GRATULATION!")
}
}
}
struct SecondView_Previews: PreviewProvider {
static var previews: some View {
SecondView()
}
}
c) MapView.swift
import SwiftUI
struct MapView: View {
var body: some View {
Text(/*#START_MENU_TOKEN#*/"Hello, World!"/*#END_MENU_TOKEN#*/)
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView()
}
}