Difference between toggle() and Toggle - swift

I am learning Modals in SwiftUI and the code is below:
ContentView.swift:
import SwiftUI
struct ContentView: View {
#State private var showingAddUser = false
var body: some View {
return VStack {
Text("Modal View")
}.onTapGesture {
self.showingAddUser.toggle()
print(self.showingAddUser) //for console
}
.sheet(isPresented: $showingAddUser) {
Addview(isPresented: self.$showingAddUser)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
AddView.swift:
import SwiftUI
struct Addview: View {
#Binding var isPresented: Bool
var body: some View {
Button("Dismiss") {
self.isPresented = false
}
}
}
struct Addview_Previews: PreviewProvider {
static var previews: some View {
Addview(isPresented: .constant(false))
}
}
When I try to run the code for the first time and check the print output in console, boolean value changes to true however if I initialise #State variable showingAddUser with true the console output is unchanged that is it remains true. Should't toggle() flip the boolean value to false?
Is this toggle() different from Toggle switch from a concept point of view?

The toggle() is a mutating function on value type Bool. If you set the initial value of showingAddUser as true it will display the AddUser View when launched initially and it's not if set to false, that's the difference.
Toggle is a SwiftUI View. It can be used as any other View in SwiftUI body, like this:
struct ContentView: View {
#State var bool: Bool
var body: some View {
Toggle(isOn: $bool) {
Text("Hello world!")
}
}
}

There is no need for isPresented Boolean in Add View
Try This
ContentView.swift
import SwiftUI
struct ContentView: View {
#State private var showingAddUser = false
var body: some View {
return VStack {
Text("Modal View")
}.onTapGesture {
self.showingAddUser = true
print(self.showingAddUser) //for console
}
.sheet(isPresented: $showingAddUser) {
Addview()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
AddView.swift
import SwiftUI
struct AddView: View {
var body: some View {
Button(action:
// Do Your Things
) {
Text("MyButton")
}
}
}
struct Addview_Previews: PreviewProvider {
static var previews: some View {
Addview()
}

Related

Trouble getting EnvironmentObject to update the UI

I originally posted another question asking this in the context of a project I was trying to develop, but I can't even get it to work in a vacuum so I figured I'd start with the basics. As the title suggests, my EnvironmentObjects don't update the UI as they should; in the following code, the user enters text on the ContentView and should be able to see that text in the next screen SecondView.
EDITED:
import SwiftUI
class NameClass: ObservableObject {
#Published var name = ""
}
struct ContentView: View {
#StateObject var myName = NameClass()
var body: some View {
NavigationView {
VStack {
TextField("Type", text: $myName.name)
NavigationLink(destination: SecondView()) {
Text("View2")
}
}
}.environmentObject(myName)
}
}
struct SecondView: View {
#EnvironmentObject var myself: NameClass
var body: some View {
Text("\(myself.name)")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(NameClass())
}
}
However, the SecondView doesn't show the text that the user has written, but the default value of name (blank). What am I doing wrong here?
class NameClass: ObservableObject {
#Published var name = ""
}
struct ContentView: View {
#StateObject var myName = NameClass()
var body: some View {
NavigationView {
VStack {
TextField("Type", text: $myName.name)
NavigationLink(destination: SecondView()) {
Text("View2")
}
}
}.environmentObject(myName)
}
}
struct SecondView: View {
#EnvironmentObject var myself: NameClass
var body: some View {
Text("\(myself.name)")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(NameClass())
}
}

How to pop NavigationLink back to ContentView when inside a loop

The answer here works tremendously but, as Im sure, is not ideal for everyone. Say ContentView2, in the link, is looping a list of NavigationLinks, when self.$isActive is true, it triggers all the NavigationLinks to open so not ideal. I've found out about using tag and selection.
// Inside a ForEach loop
// Omitted is the use of EnvironmentObject
NavigationLink(
destination: DestinationView(id: loop.id),
tag: loop.id,
selection: self.$routerState.selection,
label: {
NavCell(loopData: loop)
}
)
.isDetailLink(false)
// State:
class RouterState: ObservableObject {
//#Published var rootActive: Bool = false
#Published var tag: Int = 0
#Published var selection: Int? = nil
}
How to pop the NavigationLink when inside of a loop? The answer in the link works but not inside a loop. Is there a way to amend the answer to use both tag and selection?
Using example from link above:
import SwiftUI
struct ContentView: View {
#State var isActive : Bool = false
var body: some View {
NavigationView {
List {
/// Data from the loop will be passed to ContentView2
ForEach(0..<10, id: \.self) { num in
NavigationLink(
destination: ContentView2(rootIsActive: self.$isActive),
isActive: self.$isActive
) {
Text("Going to destination \(num)")
}
.isDetailLink(false)
}
}
}
}
}
struct ContentView2: View {
#Binding var rootIsActive : Bool
var body: some View {
NavigationLink(destination: ContentView3(shouldPopToRootView: self.$rootIsActive)) {
Text("Hello, World #2!")
}
.isDetailLink(false)
.navigationBarTitle("Two")
}
}
struct ContentView3: View {
#Binding var shouldPopToRootView : Bool
var body: some View {
VStack {
Text("Hello, World #3!")
Button (action: { self.shouldPopToRootView = false } ){
Text("Pop to root")
}
}.navigationBarTitle("Three")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Missing argument for parameter 'message' in call

I'm back with another question. I was following this guide: https://medium.com/#fs.dolphin/passing-data-between-views-in-swiftui-793817bba7b1
Everything worked from it, but the SecondView_Previews is throwing an error Missing argument for parameter 'message' in call. Here is my ContentView and SecondView
// ContentView
import SwiftUI
struct ContentView: View {
#State private var showSecondView = false
#State var message = "Hello from ContentView"
var body: some View {
VStack {
Button(action: {
self.showSecondView.toggle()
}){
Text("Go to Second View")
}.sheet(isPresented: $showSecondView){
SecondView(message: self.message)
}
Button(action: {
self.message = "hi"
}) {
Text("click me")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
import SwiftUI
struct SecondView: View {
#State var message: String
var body: some View {
Text("\(message)")
}
}
struct SecondView_Previews: PreviewProvider {
static var previews: some View {
SecondView() // Error here: Missing argument for parameter 'message' in call.
}
}
It tried changing it to SecondView(message: String) and the error changes to "Cannot convert value of type 'String.Type' to expected argument type 'String'"
Can someone please explain what I'm doing wrong, or how to correctly set up the preview. It all works fine when there's no preview. Thanks in advance!
struct ContentView: View {
#State var message: String //Define type here
var body: some View {
Text("\(message)")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(message: "Some text") //Passing value here
}
}

Switching Views With Observable Objects in SwiftUI

I am practicing trying to switch views using observable objects in SwiftUI, but my code isn't working. I know I can do this with #State, but I would like to get this working with observable objects. When I click on the image in the content view, the image doesn't change. Can someone help me?
ContentView.swift
import SwiftUI
struct ContentView: View {
#ObservedObject var viewRouter: ViewRouter
var body: some View {
VStack {
Button(action: {self.viewRouter.currentPage = "Page2"}) {
Image(viewRouter.currentPage)
}
if viewRouter.currentPage == "Page1" {
Page1(viewRouter: viewRouter)
}else if viewRouter.currentPage == "Page2" {
Page2(viewRouter: viewRouter)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(viewRouter: ViewRouter())
}
}
ViewRouter.swift
import Foundation
import SwiftUI
import Combine
class ViewRouter: ObservableObject {
let objectWillChange = PassthroughSubject<ViewRouter, Never>()
#Published var currentPage: String = "Page1"
}
Page1.swift
import SwiftUI
struct Page1: View {
#ObservedObject var viewRouter:ViewRouter
var body: some View {
VStack {
Image("ET-LondonBridge")
}
}
}
struct Page1_Previews: PreviewProvider {
static var previews: some View {
Page1(viewRouter: ViewRouter())
}
}
Page2.swift
import SwiftUI
struct Page2: View {
#ObservedObject var viewRouter:ViewRouter
var body: some View {
VStack {
Image("BigBen")
.aspectRatio(contentMode: .fit)
}
}
}
struct Page2_Previews: PreviewProvider {
static var previews: some View {
Page2(viewRouter: ViewRouter())
}
}
You don't need this line to make all things work. Just comment out this line
//let objectWillChange = PassthroughSubject<ViewRouter, Never>()

How to set an Environment Object in preview

My view needs an environment object which is set in the SceneDelegate by adding it to the window.rootViewController. How can I set an environment object to be used for the preview?
You add it using .environmentObject(_:) modifier:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(YourObject())
}
}
This userData property gets its value automatically, as long as the environmentObject(_:) modifier has been applied to a parent.
struct UserList: View {
#EnvironmentObject var userData: UserData
var body: some View {
NavigationView {
List {
Toggle(isOn: $userData.showFavoritesOnly) {
Text("Users Fav only")
}
ForEach(landmarkData) { landmark in
if !self.userData.showFavoritesOnly || landmark.isFavorite {
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
UserRow(landmark: landmark)
}
}
}
}
.navigationBarTitle(Text("Users"))
}
}
}
struct UserList_Previews: PreviewProvider {
static var previews: some View {
UserList()
.environmentObject(UserData())
}
}