Animation not working inside sheet for swiftui - ios

I am using a sheet to present a list of options and on click of the option I want to change the view with the animation of sliding from trailing. As per my understanding and what I have read on various sites I have written this code but I am not sure why it is not working the way intended. I just want to know where exactly this code went wrong.
struct XYZ: App {
let persistenceController = PersistenceController.shared
#State var isPresented : Bool = false
#State var isSwiped : Bool = false
var body: some Scene {
WindowGroup {
optionList(isPresented: $isPresented)
.sheet(isPresented: $isPresented, content: {
Text("This is from modal view!")
.onTapGesture {
withAnimation(Animation.easeIn(duration: 10)){
isSwiped.toggle()
}
}
if isSwiped {
checkedList()
.transition(.move(edge: .trailing))
}
})
}
}
}
struct optionList : View {
#Binding var isPresented : Bool
var body: some View {
Text("This is a testView")
.onTapGesture {
withAnimation{
isPresented.toggle()
}
}
}
}
struct checkedList : View {
#State var name : String = "WatchList"
var arr = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh"]
#State var mp : [Int:Int] = [:]
var body: some View {
VStack{
HStack{
TextField("WatchlistName", text: $name)
.padding(.all)
Image(systemName: "trash.fill")
.padding(.all)
.onTapGesture {
print("Delete watchList!!")
}
}
ScrollView{
ForEach(arr.indices) { item in
HStack (spacing: 0) {
Image(systemName: mp.keys.contains(item) ? "checkmark.square" : "square")
.padding(.horizontal)
Text(arr[item])
}
.padding(.bottom)
.frame(width: UIScreen.main.bounds.width, alignment: .leading)
.onTapGesture {
if mp.keys.contains(item) {
mp[item] = nil
} else {
mp[item] = 1
}
}
}
}
Button {
print("Remove Ticked Elements!")
deleteWatchListItem(arr: Array(mp.keys))
} label: {
Text("Save")
}
}
}
func deleteWatchList(ind: Int){
print(ind)
}
func deleteWatchListItem(arr : [Int]) {
print(arr)
}
}
I tried to create a view and with the animation using withanimation with a bool variable tried to change the view.

It sounds like what you want is to push the checkedList on to a NavigationStack…
struct ContentView: View {
#State var isPresented : Bool = false
var body: some View {
Text("This is a testView")
.onTapGesture {
isPresented.toggle()
}
.sheet(isPresented: $isPresented, content: {
NavigationStack {
NavigationLink("This is from modal view!") {
checkedList()
}
}
})
}
}

Related

Swiftui view doesn't refresh when navigated to from a different view

I have, what is probably, a beginner question here. I'm hoping there is something simple I'm missing or I have done wrong.
I essentially have a view which holds a struct containing an array of id strings. I then have a #FirestoreQuery which accesses a collection which holds objects with these id's. My view then displays a list with two sections. One for the id's in the original struct, and one for the remaining ones in the collection which don't appear in the array.
Each listitem is a separate view which displays the details of that item and also includes a button. When this button is pressed it adds/removes that object from the parent list and the view should update to show that object in the opposite section of the list from before.
My issue is that this works fine in the 'preview' in xcode when I look at this view on it's own. However if I run the app in the simulator, or even preview a parent view and navigate to this one, the refreshing of the view doesn't seem to work. I can press the buttons, and nothing happens. If i leave the view and come back, everything appears where it should.
I'll include all the files below. Is there something I'm missing here?
Thanks
Main view displaying the list with two sections
import SwiftUI
import FirebaseFirestoreSwift
struct SessionInvitesView: View {
#Environment(\.presentationMode) private var presentationMode
#FirestoreQuery(collectionPath: "clients") var clients : [Client]
#Binding var sessionViewModel : TrainingSessionViewModel
#State private var searchText: String = ""
#State var refresh : Bool = false
var enrolledClients : [Client] {
return clients.filter { sessionViewModel.session.invites.contains($0.id!) }
}
var availableClients : [Client] {
return clients.filter { !sessionViewModel.session.invites.contains($0.id!) }
}
var searchFilteredClients : [Client] {
if searchText.isEmpty {
return availableClients
} else {
return availableClients.filter {
$0.dogName.localizedCaseInsensitiveContains(searchText) ||
$0.name.localizedCaseInsensitiveContains(searchText) ||
$0.dogBreed.localizedCaseInsensitiveContains(searchText) }
}
}
var backButton: some View {
Button(action: { self.onCancel() }) {
Text("Back")
}
}
var body: some View {
NavigationView {
List {
Section(header: Text("Enrolled")) {
ForEach(enrolledClients) { client in
SessionInviteListItem(client: client, isEnrolled: true, onTap: removeClient)
}
}
Section(header: Text("Others")) {
ForEach(searchFilteredClients) { client in
SessionInviteListItem(client: client, isEnrolled: false, onTap: addClient)
}
}
}
.listStyle(.insetGrouped)
.searchable(text: $searchText)
.navigationTitle("Invites")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(leading: backButton)
}
}
func removeClient(clientId: String) {
self.sessionViewModel.session.invites.removeAll(where: { $0 == clientId })
refresh.toggle()
}
func addClient(clientId: String) {
self.sessionViewModel.session.invites.append(clientId)
refresh.toggle()
}
func dismiss() {
self.presentationMode.wrappedValue.dismiss()
}
func onCancel() {
self.dismiss()
}
}
struct SessionInvitesView_Previews: PreviewProvider {
#State static var model = TrainingSessionViewModel()
static var previews: some View {
SessionInvitesView(sessionViewModel: $model)
}
}
List item view
import SwiftUI
struct SessionInviteListItem: View {
var client : Client
#State var isEnrolled : Bool
var onTap : (String) -> ()
var body: some View {
HStack {
VStack(alignment: .leading) {
HStack {
Text(client.dogName.uppercased())
.bold()
Text("(\(client.dogBreed))")
}
Text(client.name)
.font(.subheadline)
}
Spacer()
Button(action: { onTap(client.id!) }) {
Image(systemName: self.isEnrolled ? "xmark.circle.fill" : "plus.circle.fill")
}
.buttonStyle(.borderless)
.foregroundColor(self.isEnrolled ? .red : .green)
}
}
}
struct SessionInviteListItem_Previews: PreviewProvider {
static func doNothing(_ : String) {}
static var previews: some View {
SessionInviteListItem(client: buildSampleClient(), isEnrolled: false, onTap: doNothing)
}
}
Higher level view used to navigate to this list view
import SwiftUI
import FirebaseFirestoreSwift
struct TrainingSessionEditView: View {
// MARK: - Member Variables
#Environment(\.presentationMode) private var presentationMode
#FirestoreQuery(collectionPath: "clients") var clients : [Client]
#StateObject var sheetManager = SheetManager()
var mode: Mode = .new
var dateManager = DateManager()
#State var viewModel = TrainingSessionViewModel()
#State var sessionDate = Date.now
#State var startTime = Date.now
#State var endTime = Date.now.addingTimeInterval(3600)
var completionHandler: ((Result<Action, Error>) -> Void)?
// MARK: - Local Views
var cancelButton: some View {
Button(action: { self.onCancel() }) {
Text("Cancel")
}
}
var saveButton: some View {
Button(action: { self.onSave() }) {
Text("Save")
}
}
var addInviteButton : some View {
Button(action: { sheetManager.showInvitesSheet.toggle() }) {
HStack {
Text("Add")
Image(systemName: "plus")
}
}
}
// MARK: - Main View
var body: some View {
NavigationView {
List {
Section(header: Text("Details")) {
TextField("Session Name", text: $viewModel.session.title)
TextField("Location", text: $viewModel.session.location)
}
Section {
DatePicker(selection: $sessionDate, displayedComponents: .date) {
Text("Date")
}
.onChange(of: sessionDate, perform: { _ in
viewModel.session.date = dateManager.dateToStr(date: sessionDate)
})
DatePicker(selection: $startTime, displayedComponents: .hourAndMinute) {
Text("Start Time")
}
.onAppear() { UIDatePicker.appearance().minuteInterval = 15 }
.onChange(of: startTime, perform: { _ in
viewModel.session.startTime = dateManager.timeToStr(date: startTime)
})
DatePicker(selection: $endTime, displayedComponents: .hourAndMinute) {
Text("End Time")
}
.onAppear() { UIDatePicker.appearance().minuteInterval = 15 }
.onChange(of: endTime, perform: { _ in
viewModel.session.endTime = dateManager.timeToStr(date: endTime)
})
}
Section {
HStack {
Text("Clients")
Spacer()
Button(action: { self.sheetManager.showInvitesSheet.toggle() }) {
Text("Edit").foregroundColor(.blue)
}
}
ForEach(viewModel.session.invites, id: \.self) { clientID in
self.createClientListElement(id: clientID)
}
.onDelete(perform: deleteInvite)
}
Section(header: Text("Notes")) {
TextField("Add notes here...", text: $viewModel.session.notes)
}
if mode == .edit {
Section {
HStack {
Spacer()
Button("Delete Session") {
sheetManager.showActionSheet.toggle()
}
.foregroundColor(.red)
Spacer()
}
}
}
}
.navigationTitle(mode == .new ? "New Training Session" : "Edit Training Session")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(
leading: cancelButton,
trailing: saveButton)
.actionSheet(isPresented: $sheetManager.showActionSheet) {
ActionSheet(title: Text("Are you sure?"),
buttons: [
.destructive(Text("Delete Session"), action: { self.onDelete() }),
.cancel()
])
}
.sheet(isPresented: $sheetManager.showInvitesSheet) {
SessionInvitesView(sessionViewModel: $viewModel)
}
}
}
func createClientListElement(id: String) -> some View {
let client = clients.first(where: { $0.id == id })
if let client = client {
return AnyView(ClientListItem(client: client))
}
else {
return AnyView(Text("Invalid Client ID: \(id)"))
}
}
func deleteInvite(indexSet: IndexSet) {
viewModel.session.invites.remove(atOffsets: indexSet)
}
// MARK: - Local Event Handlers
func dismiss() {
self.presentationMode.wrappedValue.dismiss()
}
func onCancel() {
self.dismiss()
}
func onSave() {
self.viewModel.onDone()
self.dismiss()
}
func onDelete() {
self.viewModel.onDelete()
self.dismiss()
self.completionHandler?(.success(.delete))
}
// MARK: - Sheet Management
class SheetManager : ObservableObject {
#Published var showActionSheet = false
#Published var showInvitesSheet = false
}
}
struct TrainingSessionEditView_Previews: PreviewProvider {
static var previews: some View {
TrainingSessionEditView(viewModel: TrainingSessionViewModel(session: buildSampleTrainingSession()))
}
}
I'm happy to include any of the other files if you think it would help. Thanks in advance!

SwiftUI Limit Scope of EditButton() by Platform

I am building an app for iOS and Mac Catalyst and have been able to code most of the
experience that I want except for functions that use swipe to delete in iOS.
The view includes multiple sections, each with a List and ForEach closure. I want to
be able to add the EditButton() function to the header of each section and have it
apply only to that section's List.
I can
add an EditButton() function to gain this functionality, however,
so far I have only been able to make that work for the entire screen, not for the
individual sections.
I have tried refactoring the code for each section into functions and into structs
(as shown below). In all cases the EditButton() activates the delete icons for ALL
list rows, not just the section with the button.
I have also tried placing the EditButton() inside the section in the VStack. No difference.
Here's a simple example with the latest code attempt:
struct ContentView: View {
#State private var selectedItem: String?
#State private var items = ["One", "Two", "Three", "Four", "Five"]
#State private var fruits = ["Apple", "Orange", "Pear", "Lemon", "Grape"]
var body: some View {
NavigationSplitView {
ItemSection(selectedItem: $selectedItem, items: $items)
FruitSection(selectedItem: $selectedItem, fruits: $fruits)
} detail: {
if let selectedItem {
ItemDetailView(selectedItem: selectedItem)
} else {
EmptyView()
}
}//nav
}//body
}//struct
struct ItemSection: View {
#Binding var selectedItem: String?
#Binding var items: [String]
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(items, id: \.self) { item in
NavigationLink(value: item) {
Text(item)
}
}
.onDelete { items.remove(atOffsets: $0) }
}
.listStyle(PlainListStyle())
}//v
.padding()
} header: {
HStack {
Text("Section for Items")
Spacer()
//uncomment when you have it working
//#if targetEnvironment(macCatalyst)
EditButton()
//#endif
}//h
.padding(.horizontal, 10)
}//section and header
}//body
}//item section
struct FruitSection: View {
#Binding var selectedItem: String?
#Binding var fruits: [String]
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(fruits, id: \.self) { fruit in
NavigationLink(value: fruit) {
Text(fruit)
}
}
.onDelete { fruits.remove(atOffsets: $0) }
}
.listStyle(PlainListStyle())
}//v
.padding()
} header: {
HStack {
Text("Section for Fruits")
Spacer()
}//h
.padding(.horizontal, 10)
}//section fruit
}//body
}//fruit section
struct ItemDetailView: View {
var selectedItem: String
var body: some View {
VStack {
Text(selectedItem)
Text("This is the DetailView")
}
}
}
Any guidance would be appreciated. Xcode 14.0.1 iOS 16
import SwiftUI
struct ContentView: View {
#State private var selectedItem: String?
#State private var items = ["One", "Two", "Three", "Four", "Five"]
#State private var fruits = ["Apple", "Orange", "Pear", "Lemon", "Grape"]
var body: some View {
NavigationSplitView {
ItemSection(selectedItem: $selectedItem, items: $items)
FruitSection(selectedItem: $selectedItem, fruits: $fruits)
} detail: {
if let selectedItem {
ItemDetailView(selectedItem: selectedItem)
} else {
EmptyView()
}
}//nav
}//body
}//struct
struct ItemSection: View {
#Binding var selectedItem: String?
#Binding var items: [String]
#State var isEditMode = false // this is what you need
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(items, id: \.self) { item in
NavigationLink(value: item) {
Text(item)
}
}
.onDelete { items.remove(atOffsets: $0) }
}
.environment(\.editMode, isEditMode ? .constant(.active) : .constant(.inactive)) // and set this
.listStyle(PlainListStyle())
}//v
.padding()
} header: {
HStack {
Text("Section for Items")
Spacer()
//uncomment when you have it working
//#if targetEnvironment(macCatalyst)
Button { // you also need to set EditButton() -> Button()
withAnimation {
isEditMode.toggle()
}
} label: {
Text(isEditMode ? "Done" : "Edit")
}
//#endif
}//h
.padding(.horizontal, 10)
}//section and header
}//body
}//item section
struct FruitSection: View {
#Binding var selectedItem: String?
#Binding var fruits: [String]
#State var isEditMode = false // same as this section
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(fruits, id: \.self) { fruit in
NavigationLink(value: fruit) {
Text(fruit)
}
}
.onDelete { fruits.remove(atOffsets: $0) }
}
.environment(\.editMode, isEditMode ? .constant(.active) : .constant(.inactive))
.listStyle(PlainListStyle())
}//v
.padding()
} header: {
HStack {
Text("Section for Fruits")
Spacer()
Button {
withAnimation {
isEditMode.toggle()
}
} label: {
Text(isEditMode ? "Done" : "Edit")
}
}//h
.padding(.horizontal, 10)
}//section fruit
}//body
}//fruit section
struct ItemDetailView: View {
var selectedItem: String
var body: some View {
VStack {
Text(selectedItem)
Text("This is the DetailView")
}
}
}
Here's a more general & simplified approach using PreferenceKey:
struct EditModeViewModifier: ViewModifier {
var forceEditing: Bool?
#State var isEditing = false
func body(content: Content) -> some View {
content
.onPreferenceChange(IsEditingPrefrenceKey.self) { newValue in
withAnimation {
isEditing = newValue
}
}.environment(\.editMode, .constant((forceEditing ?? isEditing) ? .active: .inactive))
}
}
extension View {
func editMode(_ editing: Bool? = nil) -> some View {
modifier(EditModeViewModifier(forceEditing: editing))
}
}
struct EditingButton: View {
#State var isEditing = false
var body: some View {
Button(action: {
isEditing.toggle()
}) {
Text(isEditing ? "Done" : "Edit")
}.preference(key: IsEditingPrefrenceKey.self, value: isEditing)
}
}
struct IsEditingPrefrenceKey: PreferenceKey {
static var defaultValue = false
static func reduce(value: inout Bool, nextValue: () -> Bool) {
value = nextValue()
}
}
You use EditingButton instead of EditButton, & use .editMode() at then end of your View. Then your sections become something like this:
struct ItemSection: View {
#Binding var selectedItem: String?
#Binding var items: [String]
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(items, id: \.self) { item in
NavigationLink(value: item) {
Text(item)
}
}.onDelete { items.remove(atOffsets: $0) }
}.listStyle(PlainListStyle())
}.padding()
} header: {
HStack {
Text("Section for Items")
Spacer()
//uncomment when you have it working
//#if targetEnvironment(macCatalyst)
EditingButton()
//#endif
}.padding(.horizontal, 10)
}.editMode()
}
}
struct FruitSection: View {
#Binding var selectedItem: String?
#Binding var fruits: [String]
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(fruits, id: \.self) { fruit in
NavigationLink(value: fruit) {
Text(fruit)
}
}.onDelete { fruits.remove(atOffsets: $0) }
}.listStyle(PlainListStyle())
}.padding()
} header: {
HStack {
Text("Section for Fruits")
Spacer()
EditingButton()
}.padding(.horizontal, 10)
}.editMode()
}
}
A more concise version of Timmy's answer uses this reusable code:
import SwiftUI
struct EditingButton: View {
#Binding var isEditing: Bool
var body: some View {
Button(isEditing ? "Done" : "Edit", action: changeEditing)
.preference(key: IsEditingPrefrenceKey.self, value: isEditing)
}
func changeEditing() { withAnimation { isEditing.toggle() } }
struct IsEditingPrefrenceKey: PreferenceKey {
static var defaultValue = false
static func reduce(value: inout Bool, nextValue: () -> Bool) { value = nextValue() }
}
}// EditingButton
extension View {
func editMode(_ editing: Bool) -> some View {
environment(\.editMode, editing ? .constant(.active) : .constant(.inactive))
}
}
Then the ItemSection is like this:
struct ItemSection: View {
#Binding var selectedItem: String?
#Binding var items: [String]
#State var isEditMode = false // this is what you need
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(items, id: \.self) { item in
NavigationLink(value: item) {
Text(item)
}
}
.onDelete { items.remove(atOffsets: $0) }
.onMove(perform: move)
}
.editMode(isEditMode)
.listStyle(PlainListStyle())
}//v
.padding()
} header: {
HStack {
Text("Section for Items")
Spacer()
EditingButton(isEditing: $isEditMode)
}//h
.padding(.horizontal, 10)
}//section and header
}// body
private func move(indexes: IndexSet, dest: Int) {
print("Move item from indexset \(indexSetList(indexes)) to index \(dest)")
items.move(fromOffsets: indexes, toOffset: dest)
}// move
}//item section
func indexSetList(_ indexes: IndexSet) -> String {
guard !indexes.isEmpty else { return "none"}
return Array(indexes).map(String.init).joined(separator: " ")
}
I have allowed drag and drop reordering to make it do what I was interested in as well.

Why fullScreenCover always take first index from array?

Why fullScreenCover always take just first index of an array?
This is some example of code:
struct TestView: View {
#State private var isFullScreen: Bool = false
var body: some View {
VStack{
ForEach(0..<5, id:\.self) { number in
VStack{
Text("\(number)")
.background(.red)
.foregroundColor(.white)
.padding(20)
.onTapGesture {
isFullScreen.toggle()
}
}
.fullScreenCover(isPresented: $isFullScreen) {
test2View(title: number)
}
}
}
}
}
This is the code of test2View:
struct test2View: View {
var title:Int
var body: some View {
Text("\(title)")
}
}
Whenever I click on any number it always show just 0, but when I make navigationLink instead of fullScreenCover, it works as expected, but navigationLink isn't a solution for my problem, I want that to be fullScreenCover.
It's because fullScreenCover is using a single isFullScreen for each number so only the first one works. Fix by adding a third intermediary View to hold an isFullScreen bool for each number, e.g.
struct TestView: View {
var body: some View {
VStack{
ForEach(0..<5) { number in
TestView2(number: number)
}
}
}
}
struct TestView2: View {
let number: Int
#State private var isFullScreen: Bool = false
var body: some View {
Text("\(number, format: .number)")
.background(.red)
.foregroundColor(.white)
.padding(20)
.onTapGesture {
isFullScreen.toggle()
}
.fullScreenCover(isPresented: $isFullScreen) {
TestView3(number: number)
}
}
}
struct TestView3: View {
let number: Int
var body: some View {
Text("\(number, format: .number)")
}
}
I found a solution using .fullScreenCover item parameter like this:
struct TestView: View {
#State private var isFullScreen: Int? = nil
var body: some View {
VStack{
ForEach(0..<5, id:\.self) { number in
VStack{
Text("\(number)")
.background(.red)
.foregroundColor(.white)
.padding(20)
.onTapGesture {
isFullScreen = number
}
}
.fullScreenCover(item: $isFullScreen) { item in
test2View(title: item)
}
}
}
}
}

SwiftUI: How to display the second Sheet when first sheet is closed

I want to make a side menu with .fullScreenCover, when a user is logged in and press MyGarage button. the .fullScreenCover will dismiss and the main view will navigate to MyGarage View. But if user is not logged in the .fullScreenCover will dismiss and a loginView with .fullScreenCover will appear. My problem is, the .fullScreenCover will not work if I put 2 same .fullScreenCover inside the main view. Is there any way to solve this? I'm sorry it's a little bit difficult for me to explain.
Here's the code
SideMenuView
struct SideMenuView: View {
#Environment(\.presentationMode) var presentationMode
#Binding var showMyGarage: Bool
#Binding var showSignIn: Bool
var user = 0 //If user is 1, it is logged in
var body: some View {
NavigationView{
VStack{
Button(action: {
presentationMode.wrappedValue.dismiss()
if user == 1 {
self.showMyGarage = true
}else{
self.showSignIn = true
}
}, label: {
Text("My Garage")
})
}
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(leading:
HStack(spacing: 20){
Button(action: {
presentationMode.wrappedValue.dismiss()
}, label: {
Text("X")
})
Text("Main Menu")
}
)
}.navigationViewStyle(StackNavigationViewStyle())
}
}
MainView
struct HomeView: View {
#State var showSideMenu = false
#State private var showMyGarage = false
#State var showSignIn = false
var body: some View {
VStack{
Text("Home")
NavigationLink(destination: MyGarageView(showMyGarage: $showMyGarage), isActive: $showMyGarage){
EmptyView()
}
}
.navigationBarItems(leading:
Button(action: {
self.showSideMenu.toggle()
}, label: {
Text("Menu")
})
)
.fullScreenCover(isPresented: $showSideMenu, content: {
SideMenuView(showMyGarage: $showMyGarage, showSignIn: $showSignIn)
})
.fullScreenCover(isPresented: $showSignIn, content: {
SignInView()
})
}
}
struct MyGarageView: View {
#Binding var showMyGarage: Bool
var body: some View {
Text("MyGarage")
}
}
struct SignInView: View {
var body: some View {
Text("Sign In")
}
}
Try to attach them to different views, like
var body: some View {
VStack{
Text("Home")
.fullScreenCover(isPresented: $showSideMenu, content: {
SideMenuView(showMyGarage: $showMyGarage, showSignIn: $showSignIn)
})
NavigationLink(destination: MyGarageView(showMyGarage: $showMyGarage), isActive: $showMyGarage){
EmptyView()
}
.fullScreenCover(isPresented: $showSignIn, content: {
SignInView()
})
}
.navigationBarItems(leading:
Button(action: {
self.showSideMenu.toggle()
}, label: {
Text("Menu")
})
)
}

How do I create a transition between from Login View to Tab View in SwiftUI?

Here's the snippet of code from LoginView:
Button(action: {
if loginAndPasswordAreOK() {
// Perform Segue to TabView
} else {
self.isValidLoginAndPassword = false
self.email = ""
self.password = ""
}
}, label: {
and there's a piece of code of MainTabView (aka Home Tab):
struct MainTabView: View {
var body: some View {
TabView {
Text("Home Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
I googled around and saw NavigationLink or something but I don't want to wrap up this transition to a NavController at all.
Here:
import SwiftUI
struct ContentView: View {
#State var isPassOk: Bool = false
var userPass: String = "1234"
#State var userGivenPass: String = ""
var body: some View {
if isPassOk == false
{
HStack
{
TextField("Enter your Pass Here!", text: $userGivenPass)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button("Log in") {
// do your logig Here!
if userGivenPass == userPass
{
withAnimation(.easeInOut)
{
isPassOk = true
}
}
else
{
isPassOk = false
}
}
}
.font(Font.title)
.padding()
}
else if isPassOk == true
{
TabView {
Text("Home Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
}
}
}
}
Here Updated for you:
import SwiftUI
struct ContentView: View {
#State var isPassOk: Bool = false
var body: some View {
if isPassOk == false
{
LogInView(isPassOk: $isPassOk)
}
else if isPassOk == true
{
MainTabView()
}
}
}
struct LogInView: View {
#Binding var isPassOk: Bool
var userPass: String = "1234"
#State var userGivenPass: String = ""
var body: some View {
HStack
{
TextField("Enter your Pass Here!", text: $userGivenPass)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button("Log in") {
// do your logig Here!
if userGivenPass == userPass
{
withAnimation(.easeInOut)
{
isPassOk = true
}
}
else
{
isPassOk = false
}
}
}
.font(Font.title)
.padding()
}
}
struct MainTabView: View {
var body: some View {
TabView {
Text("Home Tab")
.font(.system(size: 30, weight: .bold, design: .rounded))
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
}
}
}

Resources