I'm trying to put an if statement inside a NavigationLink using Xcode.
This is my code:
NavigationLink(destination: {
if location.name == "Firm of the Future" {
StartView()
} else {
Finish()
}
}, label: {
Text("Leer meer")
.font(.headline)
.frame(width: 125, height: 35)
})
With this code I'm getting the error:
Type '() -> ()' cannot conform to 'View'
But when I use this code:
NavigationLink(destination: {
if location.name == "Firm of the Future" {
Text("Screen 1")
} else {
Text("Screen 2")
}
}, label: {
Text("Leer meer")
.font(.headline)
.frame(width: 125, height: 35)
})
it works.
What am I doing wrong in the first code?
This is the code for the views:
I'm using multiple bindings.
import SwiftUI
struct StartView: View {
#State var Q1: String
#State var Q2: String
#State var Q3: String
#State var Q4: String
#State var Q5: String
#State var Q6: String
#State var Q7: String
#State var Q8: String
#State var theAnswer1: String
#State var theAnswer2: String
#State var theAnswer3: String
#State var theAnswer4: String
#State var theAnswer5: String
#State var theAnswer6: String
#State var theAnswer7: String
#State var theAnswer8: String
#State var AnsBool1: Bool
#State var AnsBool2: Bool
#State var AnsBool3: Bool
#State var AnsBool4: Bool
#State var AnsBool5: Bool
#State var AnsBool6: Bool
#State var AnsBool7: Bool
#State var AnsBool8: Bool
var body: some View {
ZStack{
Image("WolvenBack")
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea()
Image("FEClogokleur")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 70, height: 70, alignment: .leading)
.position(x: 370, y: -70)
VStack{
Spacer()
Text("De klim naar")
.font(.largeTitle)
.foregroundColor(.white)
.shadow(color: .black, radius: 10, x: 10, y: 10)
Text("het Wolvennest")
.font(.largeTitle)
.foregroundColor(.white)
.shadow(color: .black, radius: 10, x: 10, y: 10)
Spacer()
NavigationLink(
destination: FietsStap1(Q1: $Q1, Q2: Q2, Q3: Q3, Q4: Q4, Q5: Q5, Q6: Q6, Q7: Q7, Q8: Q8, theAnswer1: $theAnswer1, theAnswer2: $theAnswer2, theAnswer3: $theAnswer3, theAnswer4: $theAnswer4, theAnswer5: $theAnswer5, theAnswer6: $theAnswer6, theAnswer7: $theAnswer7, theAnswer8: $theAnswer8, AnsBool1: $AnsBool1, AnsBool2: $AnsBool2, AnsBool3: $AnsBool3,AnsBool4: $AnsBool4, AnsBool5: $AnsBool5, AnsBool6: $AnsBool6,AnsBool7: $AnsBool7,AnsBool8: $AnsBool8),
label: {
Circle()
.fill(Color(red: 0.739, green: 0.818, blue: 0.022))
.frame(width: 120, height: 200, alignment: .bottom)
.padding(10)
.shadow(color: .black, radius: 10, x: 10, y: 10)
.overlay(
Text("Start")
.font(.largeTitle)
.foregroundColor(.black)
)}
)}
}
}
}
struct StartView_Previews: PreviewProvider {
#State static var Q1 = String().self
#State static var Q2 = String().self
#State static var Q3 = String().self
#State static var Q4 = String().self
#State static var Q5 = String().self
#State static var Q6 = String().self
#State static var Q7 = String().self
#State static var Q8 = String().self
#State static var theAnswer1 = String().self
#State static var theAnswer2 = String().self
#State static var theAnswer3 = String().self
#State static var theAnswer4 = String().self
#State static var theAnswer5 = String().self
#State static var theAnswer6 = String().self
#State static var theAnswer7 = String().self
#State static var theAnswer8 = String().self
#State static var AnsBool1 = Bool().self
#State static var AnsBool2 = Bool().self
#State static var AnsBool3 = Bool().self
#State static var AnsBool4 = Bool().self
#State static var AnsBool5 = Bool().self
#State static var AnsBool6 = Bool().self
#State static var AnsBool7 = Bool().self
#State static var AnsBool8 = Bool().self
static var previews: some View {
Group {
NavigationView {
StartView(Q1: Q1, Q2: Q2, Q3: Q3, Q4: Q4, Q5: Q5, Q6: Q6, Q7: Q7, Q8: Q8, theAnswer1: theAnswer1, theAnswer2: theAnswer2, theAnswer3: theAnswer3, theAnswer4: theAnswer4, theAnswer5: theAnswer5, theAnswer6: theAnswer6, theAnswer7: theAnswer7, theAnswer8: theAnswer8, AnsBool1: AnsBool1, AnsBool2:AnsBool2,AnsBool3: AnsBool3,AnsBool4: AnsBool4, AnsBool5: AnsBool5, AnsBool6: AnsBool6,AnsBool7: AnsBool7,AnsBool8: AnsBool8)
}
}
}
}
Finish View
import SwiftUI
struct Finish: View {
var body: some View {
ZStack {
Image("WolvenBack")
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea()
.navigationBarHidden(true)
Image("FEClogokleur")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 70, height: 70, alignment: .leading)
.position(x: 410, y: 40)
VStack{
Text("")
.padding(.bottom, 140)
ScrollView {
Text("Gefeliciteerd! Je hebt de puzzel opgelost.")
.frame(width: 300)
.foregroundColor(.white)
.font(.title)
.padding(.vertical,10)
.shadow(color: .black, radius: 10, x: 10, y: 10)
Text("Je bent nu expert op het gebied van de wolf!")
.frame(width: 300)
.foregroundColor(.white)
.font(.title)
.padding(.bottom, 50)
.shadow(color: .black, radius: 10, x: 10, y: 10)
Image("Trophy")
.resizable()
.frame(width: 300, height: 250, alignment: .center)
.shadow(color: .black, radius: 10, x: 10, y: 10)
}
}
}
}
}
struct Finish_Previews: PreviewProvider {
static var previews: some View {
Finish()
}
}
In your first example, your if statement can return either a StartView or a Finish. The trouble is that the destination: block has to return a concrete type - that is, always the same type of object that conforms to the View protocol. The second example works because whatever path through the if statement is taken, it will always return a Text view.
The good news is that you can wrap your if statement in a Group – a semantically neutral view that can contain multiple types of view, but will wrap them in such a way that destination always receives the same type of view:
NavigationLink(destination: {
Group {
if location.name == "Firm of the Future" {
StartView()
} else {
Finish()
}
}
}, label: {
Text("Leer meer")
.font(.headline)
.frame(width: 125, height: 35)
})
The problem is that you are not initialising all the #State variables of StartView(). You have 24 variables not initialised and no init().
XCode always has a hard time processing Views when they are just a little bit complicated, so you see an error in the NavigationLink because it can't process its contents.
Either you put a default value on each variable, like #State var Q1: String = "", or you create an init() { }, but then you'll have to provide the values in your call to StartView(Q1: "Hello, Q2: "World", ...).
Assuming that Finish is a view... You need to provide a single view for navigation link instead of closure, so most simple fix is to use Group, like
NavigationLink(destination: Group { // << here !!
if location.name == "Firm of the Future" {
StartView()
} else {
Finish()
}
}, label: {
Text("Leer meer")
.font(.headline)
.frame(width: 125, height: 35)
})
Related
I have a dilution calculator that works with no issues. However, there is always a "0" over the placeholder in the textfield for Container Size and Dilution Ratio. I don't mind the "0", I actually want a "0" there. But I have to erase it every time I tap on the textfield to input a number. Even if I remove the placeholder it's still there. How do I make it so that I don't have to keep erasing the "0" every time I want to input a number but keep the placeholder.
struct CalculatorView: View {
#State private var containerSize = 0
#State private var dilutionRatio = 0
#State private var totalProduct = 0.0
#State private var totalWater = 0.0
#FocusState private var amountIsFocused: Bool
#FocusState private var focusedInput: Field?
func totalProductAmount() -> Double {
let firstValue = Double(containerSize)
let secondValue = Double(dilutionRatio + 1)
let totalProduct = Double(firstValue / secondValue)
return totalProduct
}
func totalWaterAmount() -> Double {
let firstValue = Double(containerSize)
let secondValue = Double(dilutionRatio + 1)
let totalProduct = Double(firstValue / secondValue)
let totalWater = Double(firstValue - totalProduct)
return totalWater
}
var body: some View {
NavigationView {
VStack(alignment: .center) {
Image("Logo")
.padding(.horizontal, 30)
HStack {
//Container Size
ZStack {
Image("Container Size (Oz)")
.padding(.vertical, -15)
TextField("", value: $containerSize, format: .number)
.frame(width: 200.0, height: 60.0)
.multilineTextAlignment(.center)
.font(Font.system(size: 50, design: .default))
.foregroundColor(.white)
.keyboardType(.decimalPad)
.focused($amountIsFocused)
.focused($focusedInput, equals: .containerSize)
}
}
//Dilution Ratio
ZStack {
Image("Dilution Ratio - 2")
.padding(.vertical, -10)
TextField("", value: $dilutionRatio, format: .number)
.frame(width: 200.0, height: 60.0)
.multilineTextAlignment(.center)
.font(Font.system(size: 50, design: .default))
.foregroundColor(.white)
.keyboardType(.decimalPad)
.focused($amountIsFocused)
.focused($focusedInput, equals: .dilutionRatio)
}
//Go Button
Button(action: {
totalProduct = totalProductAmount()
totalWater = totalWaterAmount()
amountIsFocused = false
}, label: {
Image("Go Button")
})
//Results
HStack{
ZStack {
Image("Total Product (Oz)")
Text("\(totalProduct, specifier: "%.1f")")
.font(Font.system(size: 60, design: .default))
.foregroundColor(.white)
}
ZStack {
Image("Total Water (Oz)")
Text("\(totalWater, specifier: "%.1f")")
.font(Font.system(size: 60, design: .default))
.foregroundColor(.white)
}
Make containerSize and dilutionRatio an optional Int with no default value.
#State private var containerSize: Int?
#State private var dilutionRatio: Int?
TextField("0", value: $containerSize ?? "", format: .number)
I’m working on a dilution calculator. I have it 98% working, however, I want it to work a certain way and I’m not sure to do that. This is my first app so I’m new at this.
So I want the user to be able to input the numbers and hit a button to get the calculation. I’ve been using #State and through my research and understanding, using that instantly updates any changes the user makes.
So how do I go about making the app wait till the user hits the “Go” button.
Hers my code so far.
#State private var ContainerSize = 0
#State private var DilutionRatio = 0
#State private var Go = ""
#State private var TotalProduct = 0.0
#State private var TotalWater = 0.0
#FocusState private var amountIsFocused: Bool
var totalProductAmount: Double {
let firstValue = Double(ContainerSize)
let secondValue = Double(DilutionRatio + 1)
let totalProduct = Double(firstValue / secondValue)
return totalProduct
}
var totalWaterAmount: Double {
let firstValue = Double(ContainerSize)
let secondValue = Double(DilutionRatio + 1)
let totalWater = Double(firstValue - secondValue)
return totalWater
}
//Container Size
ZStack {
Image("Container Size (Oz)")
.padding(.vertical, -15)
TextField("", value: $ContainerSize, format: .number)
.frame(width: 200.0, height: 60.0)
.multilineTextAlignment(.center)
.font(Font.system(size: 50, design: .default))
.keyboardType(.decimalPad)
.focused($amountIsFocused)
}
}
//Dilution Ratio
ZStack {
Image("Dilution Ratio - 2")
.padding(.vertical, -10)
TextField("", value: $DilutionRatio, format: .number)
.frame(width: 200.0, height: 60.0)
.multilineTextAlignment(.center)
.font(Font.system(size: 50, design: .default))
.keyboardType(.decimalPad)
.focused($amountIsFocused)
}
//Go Button
Button(action: {}, label: {
Image("Go Button")
})
//Results
HStack{
ZStack {
Image("Total Product (Oz)")
Text("\(totalProductAmount, specifier: "%.1f")")
.font(Font.system(size: 60, design: .default))
}
ZStack {
Image("Total Water (Oz)")
Text(totalWaterAmount, format: .number)
.font(Font.system(size: 60, design: .default))
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer(
Button("Done") {
amountIsFocused = false
}
}
struct CalculatorIView_Previews: PreviewProvider {
static var previews: some View {
CalculatorIView()
}
}
The calculator works as is but I want the user to input numbers, hit the “Go” button, and the results are shown.
You can create func for calculation and call it from button action. You should remove calculated properties, var totalProductAmount: Double and var totalWaterAmount: Double and do the calculation inside the function. You can check the example below.
https://www.hackingwithswift.com/quick-start/swiftui/how-to-create-a-tappable-button
var body: some View{
Button(action: {
someCalculation()
}, label: {
Image("Go Button")
})
}
func someCalculation(){
// do some calculation and you can set #State variables or you can return some value. For example 'func someCalculation()->Double'
}
So far you do the calculation in calculated properties and display them directly. So they'll update every time one of their underlying #State values change.
If you only want to show results on button press, you should display your #State result vars, and update inside the button action.
Side note: property names should start lowercase.
struct ContentView: View {
// side note: var names should start lowerCase
#State private var containerSize = 0
#State private var dilutionRatio = 0
#State private var totalProduct = 0.0
#State private var totalWater = 0.0
// for clarity change calculations to funcs
func totalProductAmount() -> Double {
let firstValue = Double(containerSize)
let secondValue = Double(dilutionRatio + 1)
let totalProduct = Double(firstValue / secondValue)
return totalProduct
}
func totalWaterAmount() -> Double {
let firstValue = Double(containerSize)
let secondValue = Double(dilutionRatio + 1)
let totalWater = Double(firstValue - secondValue)
return totalWater
}
var body: some View {
VStack {
//Container Size
Text("Container Size (Oz)")
.padding(.vertical, -15)
TextField("", value: $containerSize, format: .number)
.frame(width: 200.0, height: 60.0)
.multilineTextAlignment(.center)
.font(Font.system(size: 50, design: .default))
.keyboardType(.decimalPad)
//Dilution Ratio
Text("Dilution Ratio - 2")
.padding(.vertical, -10)
TextField("", value: $dilutionRatio, format: .number)
.frame(width: 200.0, height: 60.0)
.multilineTextAlignment(.center)
.font(Font.system(size: 50, design: .default))
.keyboardType(.decimalPad)
//Go Button
Button(action: {
// Calculate here, and set State vars with results
totalProduct = totalProductAmount()
totalWater = totalWaterAmount()
}, label: {
Text("Go Button")
})
.buttonStyle(.borderedProminent)
.padding()
//Results
// Show the state vars, not the calculation vars!
HStack{
VStack {
Text("Total Product (Oz)")
Text("\(totalProduct, specifier: "%.1f")")
.font(Font.system(size: 60, design: .default))
}
VStack {
Text("Total Water (Oz)")
Text(totalWater, format: .number)
.font(Font.system(size: 60, design: .default))
}
}
}
}
}
i am trying to add swipe inside list cell , swipe to show more options such as Delete, archive etc .
The swipe is working just fine , but the List ( vertical scroll ) is no longer scrolling up down .
Cell Bite :
import SwiftUI
struct cl_task: View {
#State private var offset: CGSize = .zero
var body: some View {
//Swipe to custom options ,by "Jack" this option not yet available in SwiftUI
let drag = DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged {
if (self.offset.width > 0 ){ return }
self.offset.width = $0.translation.width
}.onEnded {
if $0.translation.width < -100 {
self.offset = .init(width: -100, height: 0)
} else {
self.offset = .zero
}
}
ZStack{
Rectangle().foregroundColor(.blue).offset(x: offset.width, y: offset.height)
.gesture(drag)
.animation(.easeIn, value: offset)
Text("test").foregroundColor(.white)
}.frame(minWidth: 0,
maxWidth: .infinity,
minHeight: 100,
maxHeight: .infinity,
alignment: .topLeading
)
}
}
struct cl_task_Previews: PreviewProvider {
static var previews: some View {
cl_task().previewLayout(.sizeThatFits)
}
}
List main view :
struct Item {
let uuid = UUID()
let value: String
}
struct w_tasks: View {
#State private var items = [Item]()
var body: some View {
ZStack {
List(self.items, id: \.uuid) {item in
cl_task()
}
.simultaneousGesture(DragGesture().onChanged({ value in
//Scrolled
}))
VStack {
Spacer()
HStack {
Spacer()
Button(action: {
self.items.append(Item(value: "Item"))
}, label: {
Text("+")
.font(.system(size: 50))
.frame(width: 77, height: 70)
.foregroundColor(Color.white)
.padding(.bottom, 7)
})
.background(Color(hex : "#216D94"))
.cornerRadius(38.5)
.padding()
.shadow(color: Color.black.opacity(0.3),
radius: 3,
x: 3,
y: 3)
}
}
}
}
}
struct w_tasks_Previews: PreviewProvider {
static var previews: some View {
w_tasks()
}
}
I've posted my question after spending hours solving this issue as i am new to SwiftUI , any advice how to solve it ?
The solution is to give different distance for swipe, like below
struct cl_task: View {
#State private var offset: CGSize = .zero
var body: some View {
// give 25 distance makes vertical scroll enabled !!
let drag = DragGesture(minimumDistance: 25, coordinateSpace: .local)
.onChanged {
Tested with Xcode 12.4 / iOS 14.4
I'm having difficulties passing the data from the array into WeatherWidget that passes each item through WidgetView.
I believe it has something to do with how I declared #State.
// ContentView
struct WeatherWidget: View {
#State var weather = weatherData
#State var index = 0
var body: some View {
ScrollView (.vertical, showsIndicators: false){
TabView(selection: self.$index) {
ForEach(weatherData) { weather in
WidgetView(data: weather)
// Identifies current index
.tag(self.index)
}
}
.animation(.easeOut)
}
.animation(.easeOut)
}
}
// Widget
struct WidgetView: View {
#State var data: Weather
var body: some View {
HStack(alignment: .top) {
VStack(alignment: .leading) {
Text(data.temp)
.foregroundColor(.white)
.font(.system(size: 24))
.fontWeight(.semibold)
.padding(.bottom, 16)
Text(data.city)
.foregroundColor(.white)
.padding(.bottom, 4)
Text(data.range)
.foregroundColor(.gray)
}
Image(systemName: data.icon)
.font(.system(size: 32, weight: .medium))
.foregroundColor(.yellow)
}
.padding()
.frame(width: 185, height: 169)
.background(RoundedRectangle(cornerRadius: 24, style: .continuous).fill(Color.black.opacity(0.8)))
}
}
// Weather Struct
struct Weather : Hashable, Identifiable {
var id = UUID()
var temp : String
var city : String
var range : String
var icon : String
}
// Data Array
var weatherData = [
Weather(temp: "26°C", city: "Toronto, ON", range: "17°C / 28°C", icon: "sun.max"),
Weather(temp: "17°C", city: "Waterloo, ON", range: "14°C / 24°C", icon: "cloud.rain"),
Weather(temp: "31°C", city: "Whitby, ON", range: "24°C / 32°C", icon: "cloud.bolt.rain")
]
I have two textfields, assigned to:
#State private var emailAddress: String = ""
#State private var password: String = ""
Now whenever I am typing on it, the app seems to get stuck and gives me this error:
'Modifying state during view update, this will cause undefined behavior.'
I have a StartView():
class UserSettings: ObservableObject {
var didChange = PassthroughSubject<Void, Never>()
#Published var loggedIn : Bool = false {
didSet {
didChange.send(())
}
}
}
struct StartView: View {
#EnvironmentObject var settings: UserSettings
var body: some View {
if settings.loggedIn {
return AnyView(TabbarView())
}else {
return AnyView(ContentView())
}
}
}
I have created a ObservableObject class of UserSettings that has loggedIn bool value. When the user taps on 'Log In' button in LogInView(), this bool value becomes true and a new view appears (TabbarView())
This is LogInView():
struct LogInView: View {
#EnvironmentObject var settings: UserSettings
#State private var emailAddress: String = ""
#State private var password: String = ""
var body: some View {
GeometryReader { geometry in
VStack (alignment: .center){
HStack {
Image("2")
.resizable()
.frame(width: 20, height: 20)
Text("Social App")
.font(.system(size: 12))
}.padding(.top, 30)
.padding(.bottom, 10)
Text("Log In to Your Account")
.font(.title)
.font(.system(size: 14, weight: .bold, design: Font.Design.default))
.padding(.bottom, 50)
TextField("Email", text: self.$emailAddress)
.frame(width: geometry.size.width - 45, height: 50)
.textContentType(.emailAddress)
.padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 0))
.accentColor(.red)
.background(Color(red: 242 / 255, green: 242 / 255, blue: 242 / 255))
.cornerRadius(5)
TextField("Password", text: self.$password)
.frame(width: geometry.size.width - 45, height: 50)
.padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 0))
.foregroundColor(.gray)
.background(Color(red: 242 / 255, green: 242 / 255, blue: 242 / 255))
.textContentType(.password)
.cornerRadius(5)
Button(action: {
self.settings.loggedIn = true
}) {
HStack {
Text("Log In")
}
.padding()
.frame(width: geometry.size.width - 40, height: 40)
.foregroundColor(Color.white)
.background(Color.blue)
.cornerRadius(5)
}
.padding(.bottom, 40)
Divider()
Button(action: {
print("Take to forget password VC")
}) {
Text("Forgot your password?")
}
Spacer()
}
.padding(.bottom, 90)
}
}
}
I know this error appears if I am updating the view while state is being modified (when typing in textfield). But I am not updating the view anywhere in the Log In screen. Then why this error occurs. Help will be appreciated!
This works for me, you don't even need to import Combine! When you use #Published, SwiftUI will automatically synthesize the objectWillChange subject, and will call send whenever the property is mutated. You can still call .send() manually if you need to, but in most cases you won't.
class UserSettings: ObservableObject {
#Published var loggedIn : Bool = false
}
Excerpt from beta 5 release notes:
You can manually conform to ObservableObject by defining an
objectWillChange publisher that emits before the object changes.
However, by default, ObservableObject automatically synthesizes
objectWillChange and emits before any #Published properties change.
This is the full code that is working fine for me (both iPhone Xr and real device, iPad 6th Gen):
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(UserSettings()))
import SwiftUI
struct ContentView: View {
var body: some View {
StartView()
}
}
class UserSettings: ObservableObject {
#Published var loggedIn : Bool = false
}
struct StartView: View {
#EnvironmentObject var settings: UserSettings
var body: some View {
if settings.loggedIn {
return AnyView(Text("LOGGED IN"))
} else {
return AnyView(LogInView())
}
}
}
struct LogInView: View {
#EnvironmentObject var settings: UserSettings
#State private var emailAddress: String = ""
#State private var password: String = ""
var body: some View {
GeometryReader { geometry in
VStack (alignment: .center){
HStack {
Image(systemName: "2.circle.fill")
.resizable()
.frame(width: 20, height: 20)
Text("Social App")
.font(.system(size: 12))
}.padding(.top, 30)
.padding(.bottom, 10)
Text("Log In to Your Account")
.font(.title)
.font(.system(size: 14, weight: .bold, design: Font.Design.default))
.padding(.bottom, 50)
TextField("Email", text: self.$emailAddress)
.frame(width: geometry.size.width - 45, height: 50)
.textContentType(.emailAddress)
.padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 0))
.accentColor(.red)
.background(Color(red: 242 / 255, green: 242 / 255, blue: 242 / 255))
.cornerRadius(5)
TextField("Password", text: self.$password)
.frame(width: geometry.size.width - 45, height: 50)
.padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 0))
.foregroundColor(.gray)
.background(Color(red: 242 / 255, green: 242 / 255, blue: 242 / 255))
.textContentType(.password)
.cornerRadius(5)
Button(action: {
self.settings.loggedIn = true
}) {
HStack {
Text("Log In")
}
.padding()
.frame(width: geometry.size.width - 40, height: 40)
.foregroundColor(Color.white)
.background(Color.blue)
.cornerRadius(5)
}
.padding(.bottom, 40)
Divider()
Button(action: {
print("Take to forget password VC")
}) {
Text("Forgot your password?")
}
Spacer()
}
.padding(.bottom, 90)
}
}
}
I guess this is a bug. This message you got is also happening on this simple view which filters out list entries by user input. Just typing fast in the text field causes this issue. If you enter the first character into the text field, the UI stuck for some time.
struct ContentView: View {
#State private var list: [String] = (0..<500).map { "Text \($0)" }
#State private var searchText: String = ""
var filteredList: [String] {
guard !searchText.isEmpty else { return list }
return list.filter({ $0.contains(self.searchText) })
}
var body: some View {
VStack {
TextField("Search", text: $searchText)
List(filteredList, id: \String.self) { t in Text(t) }
}
.padding()
}
}
A workaround is to move the #State variables into a model. So this seems to be an issue with #State:
class Model: ObservableObject {
#Published var list: [String] = (0..<500).map { "Text \($0)" }
#Published var searchText: String = ""
var filteredList: [String] {
guard !searchText.isEmpty else { return list }
return list.filter({ $0.contains(self.searchText) })
}
}
struct ContentView: View {
#ObservedObject var model: Model
var body: some View {
VStack {
TextField("Search", text: $model.searchText)
List(model.filteredList, id: \String.self) { t in Text(t) }
}
.padding()
}
}
This may not be related to your issue, but in Xcode 11 Beta 4, Apple changed "didset" to "willset" and "didChange" to "willChange"
In Xcode 11 Beta 5, apple changed "willChange" to "objectWillChange".
Thus the StartView() should be:
class UserSettings: ObservableObject {
var objectWillChange = PassthroughSubject<Void, Never>()
#Published var loggedIn : Bool = false {
willSet {
objectWillChange.send(())
}
}
}
Don't branch with if, use .opacity(_:)
#ViewBuilder
var body: some View {
// if settings.loggedIn {
TabbarView().opacity(settings.loggedIn ? 1 : 0)
// } else {
ContentView().opacity(settings.loggedIn ? 0 : 1)
// }
}