Argument type '()' does not conform to expected type 'View' SwiftUI? - swift

I am trying to create a startup screen then animate to the mainMenu, but I get the error specified in the title. You can probably see how I am trying to do this. Please help.
struct Content: View {
#State var ShowMainMenu = false
var body: some View {
VStack {
if (ShowMainMenu) {
MainMenu()
} else {
ContentView(ToMainMenu: $ShowMainMenu)
}
}
}
}
struct ContentView: View {
#Binding var ToMainMenu:Bool
var body: some View {
VStack {
Text("I hate phone numbers")
DispatchQueue.main.asyncAfter(deadline: .now()+1.5) {
withAnimation {
self.ToMainMenu.toggle()
}
}
}
}
}

You cannot execute code in a view but you could execute something in onAppear of that view:
struct ContentView: View {
#State var ShowMainMenu = false
var body: some View {
VStack {
if (ShowMainMenu) {
Text("Hello")
} else {
Content(ToMainMenu: $ShowMainMenu)
}
}
}
}
struct Content: View {
#Binding var ToMainMenu: Bool
var body: some View {
VStack {
Text("I hate phone numbers")
}.onAppear() {
DispatchQueue.main.asyncAfter(deadline: .now()+1.5) {
withAnimation {
self.ToMainMenu.toggle()
}
}
}
}
}
Note: I had to change the names of Content and ContentView
I hope this helps.

Related

ConfirmationDialog cancel bug in swiftui

When I jump to the settings page and click Cancel in the pop-up dialog box, it will automatically return to the home page. How can I avoid this problem?
import SwiftUI
struct ContentView: View {
#State private var settingActive: Bool = false
var body: some View {
NavigationView {
TabView {
VStack {
NavigationLink(destination: SettingView(), isActive: $settingActive) {
EmptyView()
}
Button {
settingActive.toggle()
} label: {
Text("Setting")
}
}
.padding()
}
}
}
}
struct SettingView: View {
#State private var logoutActive: Bool = false
var body: some View {
VStack {
Button {
logoutActive.toggle()
} label: {
Text("Logout")
}
.confirmationDialog("Logout", isPresented: $logoutActive) {
Button("Logout", role: .destructive) {
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
This seems to be an issue with using TabView inside NavigationView.
You can solve this by moving TabView to be your top level object (where it really should be), or replacing NavigationView with the new NavigationStack.
Here's an implementation that also removes the deprecated NavigationLink method:
enum Router {
case settings
}
struct ContentView: View {
#State private var path = NavigationPath()
var body: some View {
TabView {
NavigationStack(path: $path) {
VStack {
Button {
path.append(Router.settings)
} label: {
Text("Setting")
}
}
.navigationDestination(for: Router.self) { router in
switch router {
case .settings:
SettingView(path: $path)
}
}
.padding()
}
}
}
}
struct SettingView: View {
#Binding var path: NavigationPath
#State private var logoutActive: Bool = false
var body: some View {
VStack {
Button {
logoutActive = true
} label: {
Text("Logout")
}
.confirmationDialog("Logout", isPresented: $logoutActive) {
Button("Logout", role: .destructive) {
}
}
}
}
}

Swiftui connect command to value in main view

Does someone know how to connect commands to the rest of the project?
For example: I want to toggle the AddNew variable in the content view to show the add new item sheet by using the command.
struct SampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.commands {
CommandGroup(after: CommandGroupPlacement.newItem) {
Button("Add new", action: {
self.AddNew.toggle() // should toggle variable in content View
})
}
}
}
}
struct ContentView: View {
#State var AddNew = false
var body: some View {
Button(action: {
self.AddNew.toggle()
}) {
Text("Show Detail")
}.sheet(isPresented: $AddNew) {
AddNew(dimiss: $AddNew)
}
}
}
A solution could be to have a #Published var in a class conforming to ObservableObject.
You would toggle the boolean in the class and access it from wherever you want (as an #EnvironmentObject for example).
Like this:
class AppModel: ObservableObject {
#Published var addNew: Bool = false
}
struct SampleApp: App {
#ObservedObject var model = AppModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(model)
}
.commands {
CommandGroup(after: CommandGroupPlacement.newItem) {
Button("Add new", action: {
self.model.addNew.toggle()
})
}
}
}
}
struct ContentView: View {
#EnvironmentObject var model: AppModel
var body: some View {
Button(action: {
self.model.addNew.toggle()
}) {
Text("Show Detail")
}.sheet(isPresented: $model.addNew) {
AddNew(dimiss: $model.addNew)
}
}
}

Error message: Generic parameter "FalseContent" could not be inferred

When creating a if I'm getting this error message.
The if checks if a bool, called loggedIn, is true or false.
struct ContentView: View{
#State var loggedIn = false
#State var user: BarberUser?
#State var username: String = ""
#State var password: String = ""
var body: some View{
ZStack{
Group {
if !loggedIn {
VStack{
//a TextField() is here
//a SecureField() is here
Button(action: { self.loggedIn = true }) {
Text("Log in!")
}
}
}else{
if self.user?.type = .barber{
BarberView()
} else {
ClientView()
}
}
}
}
}
}
The line that is outputting this error is:
if !loggedIn {
what is the cause of this error? And how can I fix it?
If you need more details about the code ask me and I'll provide.
Edit: added more info to the code.
The first problem is that SwiftUI frequently show errors at the wrong places. You may try to extract your subviews and it'll make your code clearer and more comfortable to find bugs.
The second one, what I see in your code snippet: the compiler should show you:
Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
if you leave just these lines of code:
struct IfElseStatementsInBody: View {
#State var loggedIn = false
var body: some View {
if !loggedIn {
VStack {
Text("Need to login")
Button(action: { self.loggedIn = true }) {
Text("Log in!")
}
}
} else {
Text("Main view")
}
}
}
The common way to avoid it is to wrap your views into AnyView. Remember, body is just a computed variable and it should know, what it need to return. The other way is to embed if...else into another view, like VStack or ZStack
struct IfElseStatementsInBody: View {
#State var loggedIn = false
var body: some View {
if !loggedIn {
return AnyView(ExtractedView(loggedIn: $loggedIn)) // how to extract subview from here
} else {
return AnyView(Text("Main view"))
}
}
}
// ... to here
struct ExtractedView: View {
#Binding var loggedIn: Bool
var body: some View {
VStack {
Text("Need to login")
Button(action: { self.loggedIn = true }) {
Text("Log in!")
}
}
}
}
// MARK: embed if...else into ZStack. in this case you'll see changing of
// "loggedIn" variable in the canvas
struct EmbedIfElseStatementsInBody: View {
#State var loggedIn = false
var body: some View {
ZStack {
if !loggedIn {
ExtractedView(loggedIn: $loggedIn)// how to extract subview from here
} else {
Text("Main view")
}
}
}
}
P.S. hope it'll help. in other way the error is in some other place, but I can't see it now because of lack of code.

SwiftUI Conditional View Transitions are not working

Consider the following code:
class ApplicationHostingView: ObservableObject {
#Published var value: Bool
}
struct ApplicationHostingView: View {
// view model env obj
var body: some View {
Group {
if applicationHostingViewModel.value {
LoginView()
.transition(.move(edge: .leading)) // <<<< Transition for Login View
} else {
IntroView()
}
}
}
}
struct IntroView: View {
// view model env obj
var body: some View {
Button(action: { applicationHostingViewModel.value = true }) {
Text("Continue")
}
}
}
struct LoginView: View {
var body: some View {
Text("Hello World")
}
}
ISSUE
In this case, I see my transition from IntroView to LoginView work fine except for any of the animations. Animations inside IntroView based on the conditionals seem to be working fine but transitions that change the entire screen don't seem to work.
change group to ZStack
add animation somewhere.
class ApplicationHostingViewModel: ObservableObject {
#Published var value: Bool = false
}
struct ApplicationHostingView: View {
// view model env obj
#ObservedObject var applicationHostingViewModel : ApplicationHostingViewModel
var body: some View {
ZStack {
if applicationHostingViewModel.value {
LoginView()
.transition(.move(edge: .leading))
} else {
IntroView(applicationHostingViewModel:applicationHostingViewModel)
}
}
}
}
struct IntroView: View {
// view model env obj
#ObservedObject var applicationHostingViewModel : ApplicationHostingViewModel
var body: some View {
Button(action: {
withAnimation(.default){
self.applicationHostingViewModel.value = true} }) {
Text("Continue")
}
}
}
struct LoginView: View {
var body: some View {
Text("Hello World").frame(maxWidth: .infinity, maxHeight: .infinity)
}
}

What is the best way to switch views in SwiftUI?

I have tried several options to switch views in SwiftUI. However, each one had issues like lagging over time when switching back and forth many times. I am trying to find the best and cleanest way to switch views using SwiftUI. I am just trying to make a multiview user interface.
In View1.swift:
import SwiftUI
struct View1: View {
#State var GoToView2:Bool = false
var body: some View {
ZStack {
if (GoToView2) {
View2()
//What should I do if I created another swiftui view under the name View2?
//Just calling View2() like that causes lag as described in the linked question before it was deleted, if from view2 I switch back to view1 and so on.
//If I directly put the code of View2 here, then adding other views would get too messy.
} else {
VStack {
Button(action: {self.GoToView2.toggle()}) {
Text("Go to view 2")
}
}
}
}
}
}
In View2.swift:
import SwiftUI
struct View2: View {
#State var GoToView1:Bool = false
var body: some View {
ZStack {
if (GoToView1) {
View1()
} else {
VStack {
Button(action: {self.GoToView1.toggle()}) {
Text("Go to view 1")
}
}
}
}
}
}
I hope the problem can be understood. To replicate the behavior, please compile the code in a SwiftUI app, then switch be repeatedly switching between the two buttons quickly for 30 seconds, then you should notice a delay between each switch, and resizing the window should look chunky. I am using the latest version of macOS and the latest version of Xcode.
So I tried to show that each of the calls to the Views would add an instance to the view stack... I might be wrong here but the following should show this:
struct View1: View {
#State var GoToView2:Bool = false
var counter: Int
init(counter: Int) {
self.counter = counter + 1
}
var body: some View {
VStack {
if (GoToView2) {
Text("\(self.counter)")
View2(counter: self.counter)
} else {
VStack {
Button(action: {
withAnimation {
self.GoToView2.toggle()
}
}) {
Text("Go to view 2")
}
}
}
}
}
}
struct View2: View {
#State var GoToView1:Bool = false
var counter: Int
init(counter: Int) {
self.counter = counter + 1
}
var body: some View {
VStack {
if (GoToView1) {
Text("\(self.counter)")
View1(counter: self.counter)
} else {
VStack {
Button(action: {
withAnimation {
self.GoToView1.toggle()
}
}) {
Text("Go to view 1")
}
}.transition(.move(edge: .leading))
}
}
}
}
The I tried to show that the other method wouldn't do that:
struct View1: View {
#State var GoToView2: Bool = false
var counter: Int
init(counter: Int) {
self.counter = counter + 1
}
var body: some View {
VStack {
if (GoToView2) {
Text("\(self.counter)")
View2(counter: self.counter, GoToView1: self.$GoToView2)
} else {
VStack {
Button(action: {
withAnimation {
self.GoToView2.toggle()
}
}) {
Text("Go to view 2")
}
}
}
}
}
}
struct View2: View {
#Binding var GoToView1: Bool
var counter: Int
init(counter: Int, GoToView1: Binding<Bool>) {
self._GoToView1 = GoToView1
self.counter = counter + 1
}
var body: some View {
VStack {
Text("\(self.counter)")
Button(action: {
withAnimation {
self.GoToView1.toggle()
}
}) {
Text("Go to view 1")
}
}.transition(.move(edge: .leading))
}
}
I don't know if the lag is really coming from this or if there is a better method of proof, but for now this is what I came up with.
Original answer
I would recommend doing the following:
struct View1: View {
#State var GoToView2:Bool = false
var body: some View {
ZStack {
if (GoToView2) {
View2(GoToView1: self.$GoToView2)
} else {
VStack {
Button(action: {
withAnimation {
self.GoToView2.toggle()
}
}) {
Text("Go to view 2")
}
}
}
}
}
}
struct View2: View {
#Binding var GoToView1: Bool
var body: some View {
VStack {
Button(action: {
withAnimation {
self.GoToView1.toggle()
}
}) {
Text("Go to view 1")
}
}.transition(.move(edge: .leading))
}
}