SwiftUI Form with Multiple EditButtons - swiftui

Trying to have a Form with multiple sections and each Section with it's own EditButton.
How to trigger a Section into "edit mode" without triggering all sections in the Form, as seen in the attached gif.
How to track if the EditButton in a certain Section is triggered so that a Button appears in that Section.
I used code from these two sources:
developer.apple.com,
stackoverflow.com
Here is the code:
import SwiftUI
struct ContentView: View {
#Environment(\.editMode) private var editMode
#State private var section1: [String] = ["Item 1", "Item 2"]
#State private var section2: [String] = ["Item 3", "Item 4"]
#State private var isEditingSection1 = false
#State private var isEditingSection2 = false
var body: some View {
Form {
// Section 1
Section (header:
EditButton().frame(maxWidth: .infinity, alignment: .trailing)
.overlay(
HStack {
Image(systemName: "folder")
.foregroundColor(Color.gray)
Text("Section 1")
.textCase(.none)
.foregroundColor(Color.gray)
}, alignment: .leading)
.foregroundColor(.blue)) {
ForEach(section1, id: \.self) { item in
Text(item)
}
.onDelete(perform: deleteSection1)
.onMove(perform: moveSection1)
// Add item option
if editMode?.wrappedValue.isEditing ?? true /*isEditingSection1*/ {
Button ("Add Item") {
// add action
}
}
}
// Section 2
Section (header:
EditButton().frame(maxWidth: .infinity, alignment: .trailing)
.overlay(
HStack {
Image(systemName: "tray")
.foregroundColor(Color.gray)
Text("Section 2")
.textCase(.none)
.foregroundColor(Color.gray)
}, alignment: .leading)
.foregroundColor(.blue)) {
ForEach(section2, id: \.self) { item in
Text(item)
}
.onDelete(perform: deleteSection2)
.onMove(perform: moveSection2)
// Add item option
if editMode?.wrappedValue.isEditing ?? true /*isEditingSection2*/ {
Button ("Add Item") {
// add action
}
}
}
}
}
func deleteSection1(at offsets: IndexSet) {
section1.remove(atOffsets: offsets)
}
func moveSection1(from source: IndexSet, to destination: Int) {
section1.move(fromOffsets: source, toOffset: destination)
}
func deleteSection2(at offsets: IndexSet) {
section2.remove(atOffsets: offsets)
}
func moveSection2(from source: IndexSet, to destination: Int) {
section2.move(fromOffsets: source, toOffset: destination)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Update for iOS 16:
I wish I knew the why, but in iOS 16 you have to phrase the boolean expression like this.
.deleteDisabled(isEditingSection2)
.deleteDisabled((isEditingSection2 || isEditingSection3))
// Etc...
In iOS 15.5 you can get away with either.
.deleteDisabled(!isEditingSection1)
// Or...
.deleteDisabled(isEditingSection2)
Here's a complete ContentView and EditButton showing this. I added a third section to help demo how the boolean OR logic should be applied inside .deleteDisabled and .moveDisabled.
import SwiftUI
struct ContentView: View {
#State private var section1: [String] = ["Item 1", "Item 2"]
#State private var section2: [String] = ["Item 3", "Item 4"]
#State private var section3: [String] = ["Item 5", "Item 6"]
#State private var isEditingSection1 = false
#State private var isEditingSection2 = false
#State private var isEditingSection3 = false
private var isEditingOn: Bool { //<=== Here
isEditingSection1 || isEditingSection2 || isEditingSection3
}
var body: some View {
Form {
// Section 1
Section (header:
EditButton(isEditing: $isEditingSection1, printBools: printBools)
.frame(maxWidth: .infinity, alignment: .trailing)
.overlay(
HStack {
Image(systemName: "folder")
.foregroundColor(Color.gray)
Text("Section 1")
.textCase(.none)
.foregroundColor(Color.gray)
}, alignment: .leading)
.foregroundColor(.blue)) {
ForEach(section1, id: \.self) { item in
Text(item)
}
.onDelete(perform: deleteSection1)
.onMove(perform: moveSection1)
.moveDisabled(isEditingSection2 || isEditingSection3) //<=== Here
.deleteDisabled((isEditingSection2 || isEditingSection3)) //<=== Here
// BIG NOTE!!
// This works in iOS 15.5, but not iOS 16: `.deleteDisabled(!isEditingSection1)`
// This works in both 15.5 and 16.0. Why??? `.deleteDisabled(isEditingSection2 || isEditingSection3)`
// Add item option
if isEditingSection1 { //<=== Here
Button ("Add Item") {
// add action
}
}
}
// Section 2
Section(header:
EditButton(isEditing: $isEditingSection2, printBools: printBools)
.frame(maxWidth: .infinity, alignment: .trailing)
.overlay(
HStack {
Image(systemName: "tray")
.foregroundColor(Color.gray)
Text("Section 2")
.textCase(.none)
.foregroundColor(Color.gray)
}, alignment: .leading)
.foregroundColor(.blue)) {
ForEach(section2, id: \.self) { item in
Text(item)
}
.onDelete(perform: deleteSection2)
.onMove(perform: moveSection2)
.moveDisabled(isEditingSection1 || isEditingSection3) //<=== Here
.deleteDisabled(isEditingSection1 || isEditingSection3) //<=== Here
// Add item option
if isEditingSection2 { //<=== Here
Button ("Add Item") {
// add action
}
}
}
// Section 3
Section(header:
EditButton(isEditing: $isEditingSection3, printBools: printBools)
.frame(maxWidth: .infinity, alignment: .trailing)
.overlay(
HStack {
Image(systemName: "tray")
.foregroundColor(Color.gray)
Text("Section 3")
.textCase(.none)
.foregroundColor(Color.gray)
}, alignment: .leading)
.foregroundColor(.blue)) {
ForEach(section3, id: \.self) { item in
Text(item)
}
.onDelete(perform: deleteSection3)
.onMove(perform: moveSection3)
.moveDisabled(isEditingSection1 || isEditingSection2) //<=== Here
.deleteDisabled(isEditingSection1 || isEditingSection2) //<=== Here
// Add item option
if isEditingSection3 { //<=== Here
Button ("Add Item") {
// add action
}
}
}
}.environment(\.editMode, isEditingOn ? .constant(.active) : .constant(.inactive)) //<=== Here
}
func deleteSection1(at offsets: IndexSet) {
section1.remove(atOffsets: offsets)
}
func moveSection1(from source: IndexSet, to destination: Int) {
section1.move(fromOffsets: source, toOffset: destination)
}
func deleteSection2(at offsets: IndexSet) {
section2.remove(atOffsets: offsets)
}
func moveSection2(from source: IndexSet, to destination: Int) {
section2.move(fromOffsets: source, toOffset: destination)
}
func deleteSection3(at offsets: IndexSet) {
section3.remove(atOffsets: offsets)
}
func moveSection3(from source: IndexSet, to destination: Int) {
section3.move(fromOffsets: source, toOffset: destination)
}
func printBools() {
// let _ = print("isEditingSection1 = \(isEditingSection1)")
// let _ = print("isEditingSection2 = \(isEditingSection2)")
}
}
struct EditButton: View {
#Binding var isEditing: Bool
let printBools: () -> Void
var body: some View {
Button(isEditing ? "DONE" : "EDIT") {
printBools()
withAnimation {
isEditing.toggle()
}
printBools()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Note that logically here, both expressions !isEditingSection1 and isEditingSection2 || isEditingSection3 are equivalent when we consider how we are using them here.
isEditingSection1
! isEditingSection1
isEditingSection2 OR isEditingSection3
true
false
false
false
true
true, if editing another section. Otherwise false.

There is no inbuilt thing for set different editing mode for each section.
But you can use it explicitly to set editing mode and disable/enable delete and move action for each row.
Here is the possible solution demo.
For this, you need to first create your own EditButton with a binding bool value.
struct EditButton: View {
#Binding var isEditing: Bool
var body: some View {
Button(isEditing ? "DONE" : "EDIT") {
withAnimation {
isEditing.toggle()
}
}
}
}
Now your Form view is.
struct ContentViewEditModeDemo: View {
#State private var section1: [String] = ["Item 1", "Item 2"]
#State private var section2: [String] = ["Item 3", "Item 4"]
#State private var isEditingSection1 = false
#State private var isEditingSection2 = false
private var isEditingOn: Bool { //<=== Here
isEditingSection1 || isEditingSection2
}
var body: some View {
Form {
// Section 1
Section (header:
EditButton(isEditing: $isEditingSection1).frame(maxWidth: .infinity, alignment: .trailing) //<=== Here
.overlay(
HStack {
Image(systemName: "folder")
.foregroundColor(Color.gray)
Text("Section 1")
.textCase(.none)
.foregroundColor(Color.gray)
}, alignment: .leading)
.foregroundColor(.blue)) {
ForEach(section1, id: \.self) { item in
Text(item)
}
.onDelete(perform: deleteSection1)
.onMove(perform: moveSection1)
.moveDisabled(!isEditingSection1) //<=== Here
.deleteDisabled(!isEditingSection1) //<=== Here
// Add item option
if isEditingSection1 { //<=== Here
Button ("Add Item") {
// add action
}
}
}
// Section 2
Section(header:
EditButton(isEditing: $isEditingSection2).frame(maxWidth: .infinity, alignment: .trailing) //<=== Here
.overlay(
HStack {
Image(systemName: "tray")
.foregroundColor(Color.gray)
Text("Section 2")
.textCase(.none)
.foregroundColor(Color.gray)
}, alignment: .leading)
.foregroundColor(.blue)) {
ForEach(section2, id: \.self) { item in
Text(item)
}
.onDelete(perform: deleteSection1)
.onMove(perform: moveSection1)
.moveDisabled(!isEditingSection2) //<=== Here
.deleteDisabled(!isEditingSection2) //<=== Here
// Add item option
if isEditingSection2 { //<=== Here
Button ("Add Item") {
// add action
}
}
}
}.environment(\.editMode, isEditingOn ? .constant(.active) : .constant(.inactive)) //<=== Here
}
func deleteSection1(at offsets: IndexSet) {
section1.remove(atOffsets: offsets)
}
func moveSection1(from source: IndexSet, to destination: Int) {
section1.move(fromOffsets: source, toOffset: destination)
}
func deleteSection2(at offsets: IndexSet) {
section2.remove(atOffsets: offsets)
}
func moveSection2(from source: IndexSet, to destination: Int) {
section2.move(fromOffsets: source, toOffset: destination)
}
}

Related

View not refreshing when Core Data are updated via another function

EDIT: added more context
I have a List in the ContentView which shows a list of Core Data items. In the list I call the function that should show if one of those items has a "check" that day ( imagine a checklist app ).
The statusView works ok when it loads but it does not refresh when , from a button on the ContentView I create an entry that should effect the fetchRequest.
What I am doing wrong?
This is the statusView:
struct statusView: View {
#FetchRequest var fetchRequest: FetchedResults<Check>
let dateFormatter = DateFormatter()
var body: some View {
if(fetchRequest.count > 0 ) {
Image(systemName: "checkmark")
.imageScale(.large)
.font(.title2)
.foregroundColor(Color(.sRGB, red: 91/255, green: 200/255, blue: 175/255))
} else {
Image(systemName: "exclamationmark.circle")
.imageScale(.large)
.font(.title2)
.foregroundColor(Color.yellow)
}
}
init(filter: String) {
let p1 = NSPredicate(format: "habit_id == %#", filter)
let p2 = NSPredicate(format: "date >= %# && date <= %#", Calendar.current.startOfDay(for: Date()) as CVarArg, Calendar.current.startOfDay(for: Date() + 86400) as CVarArg)
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [p1, p2])
_fetchRequest = FetchRequest<Check>(sortDescriptors: [], predicate: predicate)
dateFormatter.dateFormat = "dd/MM/YY"
}
}
and this is the ContentView that is calling the statusView
import SwiftUI
import CoreData
struct ContentView: View {
#Environment(\.managedObjectContext) var moc
#FetchRequest(sortDescriptors: []) var habits: FetchedResults<Habit>
#FetchRequest(sortDescriptors: []) var checks: FetchedResults<Check>
#FetchRequest(sortDescriptors: []) var todayChecks: FetchedResults<Check>
#State private var thisID: String = ""
#State private var selection: String? = nil
#State private var title = ""
#State private var forceRefresh = ""
var color_purple: Color = Color(.sRGB, red: 161/255, green: 78/255, blue: 191/255)
func createCheckToday(habit_id: UUID) {
let new_check = Check(context: moc)
new_check.id = UUID()
new_check.date = Date()
new_check.habit_id = habit_id
try? moc.save()
}
func deleteHabit(obj: NSManagedObject) {
moc.delete(obj)
try! moc.save()
}
func _riga(title: String, subtitle: String, id: UUID, obj: NSManagedObject) -> some View {
print(id.uuidString)
var body: some View {
Button {
createCheckToday(habit_id: id)
} label: {
HStack {
//statusView(filter: id.uuidString)
VStack(alignment: .leading) {
Text(title)
.font(.headline)
Text(subtitle)
.font(.subheadline)
}
}
}
}
return body
}
func delete(at offsets: IndexSet) {
// delete the objects here
}
var body: some View {
NavigationView {
VStack {
Text("")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
HStack {
Image(systemName: "note")
.imageScale(.large)
.font(.title2)
.foregroundColor(Color(.sRGB, red: 161/255, green: 78/255, blue: 191/255))
Text("Habit-o")
.font(Font.system(.largeTitle, design: .rounded).weight(.heavy))
.foregroundColor(Color(.sRGB, red: 161/255, green: 78/255, blue: 191/255))
.padding(10)
}
}
}
//---
List(habits) { habit in
HStack {
statusView(filter: habit.id!.uuidString)
_riga(title: habit.title!, subtitle: habit.subtitle!, id: habit.id!, obj: habit)
}
}
.listStyle(.plain)
Spacer()
//---
NavigationLink(destination: newForm(), tag: "A", selection: $selection) { EmptyView() }
Button(action: {
selection="A"
}) {
Text("New Habit")
.font(.title)
.fontWeight(.heavy)
.padding()
.background(color_purple)
.cornerRadius(40)
.foregroundColor(Color.white)
.padding(10)
.overlay(
RoundedRectangle(cornerRadius: 40)
.stroke(Color.purple, lineWidth: 5)
)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
//---->
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

List ForEach Problem SwiftUI - ListCells are not visible with List

I realized that when I use nested List - ForEach, I can not see anything inside these codes. But when I remove List I can see all elements inside the view. Unfortunately, without using List I can not use .onDelete and that is a problem.
struct ListsInfoView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(entity:CDListModel.entity(),
sortDescriptors: [
NSSortDescriptor(
keyPath:\CDListModel.title,
ascending: true )
]
)var lists: FetchedResults<CDListModel>
#State var isListSelected = false
#State var selectedList : CDListModel!
var body: some View {
List{
ForEach(lists) { list in
Button(action: {
self.selectedList = list
self.isListSelected.toggle()
}) {
ListCell(list: list)
}
}
.onDelete(perform: deleteList)
}
.listStyle(PlainListStyle())
.fullScreenCover(isPresented: $isListSelected) {
ListDetailView(selectedList: $selectedList)
.environment(\.managedObjectContext, viewContext)
}
}
func deleteList(at offsets: IndexSet) {
viewContext.delete(lists[offsets.first!])
PersistenceController.shared.saveContext()
}
}
Like above, I do not see any ListCell but when I remove List { } it is all perfect. Why is that?
My ListCell
struct ListCell: View {
#ObservedObject var list : CDListModel
var body: some View {
HStack{
Image(systemName: "folder")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30, alignment: .center)
.foregroundColor(.yellow)
Text(list.title ?? "")
.foregroundColor(.black)
.font(.system(size: 20, weight: .regular, design: .rounded))
.padding(.leading,10)
Spacer()
Text(String(list.notes?.count ?? 0))
.foregroundColor(.gray)
Image(systemName: "chevron.right")
.foregroundColor(.gray)
}
.padding(.horizontal)
}
}
This is my MainView that I call ListsView. Inside of the ListView I am calling ListInfoView if isShowTapped
struct MainView: View {
#Environment(\.managedObjectContext) private var viewContext
#State var searchText = ""
#State var newFolderName = ""
#State var isAddList : Bool = false
#State var isAddNote: Bool = false
var body: some View {
ZStack{
Color(.white)
.edgesIgnoringSafeArea(.all)
NavigationView{
VStack(alignment: .leading){
ScrollView{
SearchBar(text: $searchText)
.environment(\.managedObjectContext, viewContext)
ListsView()
.environment(\.managedObjectContext, viewContext)
ListView
struct ListsView: View {
#Environment(\.managedObjectContext) private var viewContext
#State var isShowTapped: Bool = false
#State var selectedIndex : Int = 0
var body: some View {
VStack {
Spacer()
HStack{
Text("On My iPhone")
.font(.system(size: 20, weight: .semibold, design: .rounded))
Spacer()
Button(action: {
withAnimation{
self.isShowTapped.toggle()
print("slider button tapped")
}
}, label: {
Image(systemName:isShowTapped ? "chevron.down" : "chevron.right")
.foregroundColor(.black)
})
}
.padding(.horizontal)
if isShowTapped {
ListsInfoView()
.environment(\.managedObjectContext, viewContext)
.transition(.scale)
} else {}
Spacer()
}
}
}

SwiftUI TabView not working, it just shows text off screen

I am trying to get a TabView in SwiftUI, but it just doesn't work... My code is here:
import SwiftUI
import SDWebImage
import HalfModal
struct ContentView: View {
#State var launches: [Launch] = []
// #State private var showingAlert = false
#State private var show_modal: Bool = false
#State private var mName: String = ""
#State private var mDate: String = ""
#State private var rID: String = ""
#State private var mImg: String = ""
#State private var mDesc: String = ""
#State private var showingHalfModal: Bool = false
#State private var choices = ["Launches", "Rockets"]
#State private var choice = 0
var rocketNames = ["5e9d0d95eda69955f709d1eb": "Falcon 1", "5e9d0d95eda69973a809d1ec": "Falcon 9", "5e9d0d95eda69974db09d1ed": "Falcon Heavy", "5e9d0d96eda699382d09d1ee": "Starship"]
init() {
UITableView.appearance().separatorStyle = .none
UITableViewCell.appearance().backgroundColor = .clear
UITableView.appearance().backgroundColor = .clear
}
var body: some View {
// Spacer()
// .frame(height: 100)
TabView {
Group {
NavigationView {
ZStack {
VStack {
// Spacer()
// .frame(height: 10)
// Text("SpaceX launch list")
// .font(.largeTitle)
Spacer()
.frame(height: 1)
.navigationBarTitle("Launches")
List {
ForEach(launches, id: \.id) { launch in
// Text("image")
// Image("imagenotfound")
Button(action: {
self.mName = launch.name
self.mDate = Date(timeIntervalSince1970: launch.date_unix).getFormattedDate(format: "dd/MM/yyyy HH:mm:ss")
self.rID = launch.rocket
self.mImg = launch.links.patch.missionPatch ?? "null"
self.mDesc = launch.details ?? "No description"
// sleep(1)
self.show_modal.toggle()
withAnimation {
self.showingHalfModal = true
}
}) {
HStack {
// Image("imagenotfound")
// .resizable()
// .frame(width: 50, height: 50)
URLimageView(urlString: launch.links.patch.missionPatch)
// .frame(width: 50, height: 50)
Group {
Text(launch.name)
.font(.system(size: 23))
.frame(maxWidth: .infinity, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
Text(Date(timeIntervalSince1970: launch.date_unix).getFormattedDate(format: "dd/MM/yyyy HH:mm:ss"))
.font(.system(size: 11.5))
.foregroundColor(Color.gray)
.frame(maxWidth: .infinity, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
Spacer()
}
}
}
.buttonStyle(PlainButtonStyle())
// .sheet(isPresented: self.$show_modal) {
// // ModalView(mission: launch.name, date: Date(timeIntervalSince1970: launch.date_unix).getFormattedDate(format: "dd/MM/yyyy HH:mm:ss"), rocket: launch.rocket)
// ModalView(mission: mName, date: mDate, rocket: rID)
// }
}
}.onAppear {
apiCall().getUsers{ (launches) in self.launches = launches}
}.listStyle(SidebarListStyle())
.frame(alignment: .center)
}
if showingHalfModal {
HalfModalView(content: AnyView(VStack(alignment: .leading) {
Text(mDesc)
.padding()
}), header: AnyView(HStack {
URLimageView(urlString: self.mImg)
VStack(alignment: .leading) {
Text(self.mName)
Text(self.mDate)
.font(.system(size: 10))
.foregroundColor(Color.gray)
}}), isPresented: $showingHalfModal)
}
}
}
}
}
.tabItem {
Image(systemName: "flame")
Text("Launches")
}
Text("rockets")
.tabItem {
Image(systemName: "paperplane")
Text("Rockets")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension Date {
func getFormattedDate(format: String) -> String {
let dateformat = DateFormatter()
dateformat.dateFormat = format
return dateformat.string(from: self)
}
}
I have tried following numerous tutorials that show that they get successful results, but mine still doesn't work...
Screenshot of issue:
It should show 2 tabs: Launches and Rockets... Any ideas on how to get it working?
Your view is too complex and you misplaced some subviews. If you clear the body a little bit, you can see that you attached tabItem modifiers outside the TabView:
var body: some View {
TabView {
Group {
NavigationView {
// ...
}
}
}
.tabItem {
Image(systemName: "flame")
Text("Launches")
}
Text("rockets")
.tabItem {
Image(systemName: "paperplane")
Text("Rockets")
}
}
Instead, try the following structure:
var body: some View {
TabView {
NavigationView {
// ...
}
.tabItem {
Image(systemName: "flame")
Text("Launches")
}
Text("rockets")
.tabItem {
Image(systemName: "paperplane")
Text("Rockets")
}
}
}
Note: I recommend you extract some views as subviews. Some examples can be found here:
SwiftUI - Can I share functions with an extracted subview?

Result of 'View' initializer is unused

My Custom button does not tap and passes to next view called AddCreditCardView.
I have tested the button action with print statement and it won't work too.
I copied my code below in separate.
This is my ContentView
import SwiftUI
struct ContentView: View {
let membershipRows = MembershipData.listData()
let corporateRows = CorporateData.listData()
let otherOperationRows = OtherOperationsData.listData()
#State var selectedCard = CreditCard(id: "", cardOwnerName: "", cardNumber: "", cardExpMonth: "", cardExpYear: "", ccv: "")
#State var shown: Bool = false
var body: some View {
NavigationView {
VStack {
List {
Section(header: Text("Bireysel")) {
ForEach(membershipRows) { row in
NavigationLink(destination: CreditCardView()) {
RowElementView(row: row)
}
}
}
if self.corporateRows.count == 0
{
Rectangle()
.background(Color(.white))
.edgesIgnoringSafeArea(.all)
.foregroundColor(.white)
.padding(.vertical,32)
}
else {
Section(header: Text("Kurumsal")) {
ForEach(corporateRows) { row in
RowElementView(row: row)
}
}
}
Section(header: Text("Diger Islemler")) {
ForEach(otherOperationRows) { row in
RowElementView(row: row)
}
}
Rectangle()
.foregroundColor(.clear)
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height )
}
.navigationBarTitle("Odeme Yontemleri", displayMode: .inline)
.font(Font.custom("SFCompactDisplay", size: 16))
Button(action: {
AddCreditCardView(item: self.selectedCard)
}, label: { CustomButton(title: "Odeme Yontemi Ekle", icon: .none, status: .enable)
})
}
}
}
This is my AddCreditCardView
import SwiftUI
struct AddCreditCardView: View {
var item: CreditCard
var body: some View {
NavigationView {
VStack {
TopBar()
Spacer()
CardInfo()
Spacer()
}
.navigationBarTitle("Odeme Yontemi", displayMode: .inline)
}
}
}
struct TopBar : View {
var body: some View {
VStack {
HStack() {
Image("addcreditcard")
Image("line")
Image("locationBar")
Image("line")
Image("check-circle")
}
.padding(.horizontal,62)
VStack {
Text("Kredi Karti Ekle")
.font(Font.custom("SFCompactDisplay-Bold", size: 14))
Text("1. Adim")
.font(Font.custom("SFCompactDisplay", size: 14))
.fontWeight(.regular)
.foregroundColor(.gray)
}
}
.padding()
}
}
struct CardInfo : View {
var body: some View {
VStack {
CustomTextField(tFtext: "Kartin Uzerindeki Isim", tFImage: "user")
.textContentType(.givenName)
CustomTextField(tFtext: "Kredi Kart Numarasi", tFImage: "credit")
.textContentType(.oneTimeCode)
.keyboardType(.numberPad)
HStack {
CreditCardDateTextField(tFtext: "", tFImage: "date")
.textContentType(.creditCardNumber)
Spacer()
Text("|")
.foregroundColor(.black)
.overlay(
Rectangle()
.frame(width: 60, height: 53))
CustomTextField(tFtext: "CCV", tFImage: "")
.textContentType(.creditCardNumber)
}
.foregroundColor(Color(#colorLiteral(red: 0.9647058824, green: 0.9725490196, blue: 0.9882352941, alpha: 1)))
CustomTextField(tFtext: "Kart Ismi", tFImage: "cardEdit")
Spacer()
}
}
}
And Finally, this is my CreditCard Model
import SwiftUI
struct CreditCard: Identifiable {
var id: String = UUID().uuidString
var cardOwnerName : String
var cardNumber: String
var cardExpMonth: String
var cardExpYear: String
var ccv: String
Seems like you are trying to navigate to AddCreditCardView on the button press. The action closure can not present a view automatically like that! You should change that code to something like this:
#State var navigated = false
,,,
NavigationLink("AddCreditCardView", destination: AddCreditCardView(), isActive: $navigated)
Button(action: { self.navigated.toggle() },
label: { CustomButton(title: "Odeme Yontemi Ekle", icon: .none, status: .enable) })
changing the navigated state will show the next page as it seems you wished.

Using SwiftUI. My Slider/Side-menu launches new Views just fine when clicked but click <back> button and now all the options are 'dead'

Using SwiftUI and a slider/side menu tutorial that I have augmented in order to put actions on each of the side menu selections.
When the side menu is displayed and I tap a menu option, it works great and takes me to a new view with a menu item. But when i tap on and see the side menu still in place, all the menu items are not dead. The menu items still animate a click (with a flicker) but nothing happens. I have to close the side menu, reopen it, and then the menu items work once again - one time.
Can anyone tell me why this is happening?
Here is the pretty contentview, the mainview, and the sidemenu view.
//ContentView.swift
import SwiftUI
struct ContentView: View {
#State var showMenu = false
var body: some View {
let drag = DragGesture()
.onEnded {
if $0.translation.width < -100 {
withAnimation {
self.showMenu = false
}
}
}
return NavigationView {
GeometryReader { geometry in
ZStack(alignment: .leading) {
MainView(showMenu: self.$showMenu)
.frame(width: geometry.size.width, height: geometry.size.height)
.offset(x: self.showMenu ? geometry.size.width/2 : 0)
.disabled(self.showMenu ? true : false)
if self.showMenu {
MenuView()
.frame(width: geometry.size.width/2)
.transition(.move(edge: .leading))
}
}
.gesture(drag)
}
.navigationBarTitle("Side Menu", displayMode: .inline)
.navigationBarItems(leading: (
Button(action: {
withAnimation {
self.showMenu.toggle()
}
}) {
Image(systemName: "line.horizontal.3")
.imageScale(.large)
}
))
}
}
}
struct MainView: View {
#Binding var showMenu: Bool
var body: some View {
Button(action: {
withAnimation {
self.showMenu = true
}
}) {
Text("Show Menu")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and here is the sidemenu view.
//MenuView.swift
import SwiftUI
struct PlayerView: View {
#State var showMenu = true
//#EnvironmentObject var session: SessionStore
var body: some View {
VStack{
//self.showMenu = true
Text("Manage Players Here").foregroundColor(.red)
}
}
}
struct MenuView: View {
#State var showMenu = true
var body: some View {
VStack(alignment: .leading) {
HStack() {
NavigationLink(destination: PlayerView()) {
HStack(){
Image(systemName: "person")
.foregroundColor(.gray)
.imageScale(.large)
Text("Players")
.foregroundColor(.gray)
.font(.headline)
}
}
}
.padding(.top, 100)
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(red: 32/255, green: 32/255, blue: 32/255))
.edgesIgnoringSafeArea(.all)
}
}
struct MenuView_Previews: PreviewProvider {
static var previews: some View {
MenuView()
}
}
enter code here
1) Binding var in the MenuView
2) OnAppear{} with Zstack to turn off the showMenu
struct ContentView: View {
#State var showMenu = false
var body: some View {
let drag = DragGesture()
.onEnded {
if $0.translation.width < -100 {
withAnimation {
self.showMenu = false
}
}
}
return NavigationView {
GeometryReader { geometry in
ZStack(alignment: .leading) {
MainView(showMenu: self.$showMenu)
.frame(width: geometry.size.width, height: geometry.size.height)
.offset(x: self.showMenu ? geometry.size.width/2 : 0)
.disabled(self.showMenu ? true : false)
if self.showMenu {
MenuView(showMenu: self.$showMenu)
.frame(width: geometry.size.width/2)
.transition(.move(edge: .leading))
}
}
.gesture(drag).onAppear {
self.showMenu = false
}
}
.navigationBarTitle("Side Menu", displayMode: .inline)
.navigationBarItems(leading: (
Button(action: {
withAnimation {
self.showMenu.toggle()
}
}) {
Image(systemName: "line.horizontal.3")
.imageScale(.large)
}
))
}
}
}
struct MainView: View {
#Binding var showMenu: Bool
var body: some View {
Button(action: {
withAnimation {
self.showMenu = true
}
}) {
Text("Show Menu")
}
}
}
struct PlayerView: View {
#State var showMenu = true
//#EnvironmentObject var session: SessionStore
var body: some View {
VStack{
//self.showMenu = true
Text("Manage Players Here").foregroundColor(.red)
}
}
}
struct MenuView: View {
#Binding var showMenu: Bool // = true
var body: some View {
VStack(alignment: .leading) {
HStack() {
NavigationLink(destination: PlayerView()) {
HStack(){
Image(systemName: "person")
.foregroundColor(.gray)
.imageScale(.large)
Text("Players")
.foregroundColor(.gray)
.font(.headline)
}
}
}
.padding(.top, 100)
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(red: 32/255, green: 32/255, blue: 32/255))
.edgesIgnoringSafeArea(.all)
}
}