Looping multiple arrays with ForEach SwiftUI - arrays

UI: https://imgur.com/a/0BbJBFc
I'm using the ForEach to iterate over an array of minerals in the example code, but I can't find a proper solution to loop the second array (mineral amount) right underneath the minerals.
In different project, I made it so far that the ForEach loops both arrays but for every mineral displays all amount for the Planet and for the second mineral all amount for the Planet and so on.
I did create a new struct with both arrays but without success. Adding a binding property also failed. I hope to learn a new swift method to achieve the desire look.
Data File
import Foundation
struct Planet: Identifiable {
var id = UUID()
var name: String
var minerals: [String]
var mineralAmount: [String]
}
let planetsData: [Planet] = [
Planet(name: "Jupiter", minerals: ["Iron", "Gold", "Copper"], mineralAmount: ["10K", "20K", "30K"]),
Planet(name: "Earth", minerals: ["Lithium", "Aluminium", "Quartz"], mineralAmount: ["40K", "50K", "60K"])
]
ContentView
import SwiftUI
struct ContentView: View {
var planet: Planet
var body: some View {
VStack() {
ForEach(planet.minerals, id: \.self) { item in
Text(item)
.font(.system(size: 22, weight: .regular))
.foregroundColor(.primary)
Text("amount to be added")
.font(.system(size: 22, weight: .regular))
.foregroundColor(.primary)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(planet: planetsData[0])
}
}
[1]: https://i.stack.imgur.com/4MDKs.png

You can achieve it this way:
ScrollView {
VStack (alignment: .leading) {
ForEach(0..<planet.minerals.count) { i in
HStack {
Circle()
.frame(width: 50, height: 50)
.foregroundColor(.black)
VStack (alignment: .leading) {
Text(planet.minerals[i])
.font(.system(size: 22, weight: .regular))
.foregroundColor(.primary)
Text(planet.mineralAmount[i])
.font(.system(size: 22, weight: .regular))
.foregroundColor(.secondary)
}
}
}
Spacer()
}
}

why don't you create a dictionary from both values
mineralsDic = [minerals: mineralAmount]
I of course know the syntax of dictionary but I just try to explain my idea + instead of making 2 loops you can make only one which has less complexity and better performance

Related

My Array can be used for one section of my code, but not the other?

I am making a location finder app using SwiftUI, and have my locations hard-coded into an array called 'locations'
Example:
var locations = [
Location(image: "The Ivy", title: "The Ivy", tag: "Bar", price: 3, coordinate: CLLocationCoordinate2D(latitude: -33.86633754527662, longitude: 151.20748914919602), description: "Stylish restaurants, a hip rooftop pool bar & big club nights in a landmark entertainment complex."),
]
struct Location : Identifiable {
var id = UUID().uuidString
var image : String
var title : String
var tag : String
var price : Int
var coordinate: CLLocationCoordinate2D
var description : String
}
I have a grid of locations on the home screen that already uses this code to create Detail views of each location using Lazy Grids.
Example:
// GRID...
LazyHGrid(rows: Array(repeating: GridItem(.flexible(),spacing: 15), count: 1), spacing: 30){
// Sample Locations...
ForEach(locations){location in
// Location View...
LocationGrid(location: location)
}
}
The issue is that I have a map, which has location pins placed on it which it grabs from the array. But when I try and get those pins to link to a detail view, an error shows saying that "location" was not found in scope. I don't get how I'm using "location" in literally the line above perfectly fine, but its not found when I want to use it again a line later.
It's probably some silly error on my part but any solution would be much appreciated.
Map code:
import SwiftUI
import MapKit
struct MapView: View {
#State var detail = false
#Environment(\.presentationMode) var presentationMode:Binding<PresentationMode>
#State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: -33.8688, longitude: 151.2093), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
var body: some View {
VStack {
ZStack {
Map(coordinateRegion: $region, annotationItems: locations) {
MapAnnotation(coordinate: $0.coordinate) {
Button {
detail.toggle()
} label: {
Image("Pin")
.renderingMode(.template)
.resizable()
.foregroundColor(.red)
.frame(width: 30, height: 30)
}
}
}
.frame(width: 420, height: 910)
.ignoresSafeArea()
HStack {
Button(action: {self.presentationMode.wrappedValue.dismiss()}) {
Image(systemName: "chevron.left")
.font(.system(size: 34, weight: .bold))
.foregroundColor(Color("Text_LightWhenDark"))
.padding(.all, 20)
.background(Color("top"))
.clipShape(RoundedRectangle(cornerRadius: 25.0))
}
.offset(x: -150, y: -380)
}
.padding([.horizontal,.top])
}
}
.navigationBarTitle("")
.navigationBarHidden(true)
.fullScreenCover(isPresented: $detail) {
DetailView(location: location)
}
}
}
Error appears at DetailView(location: location)

Sheetview with zipped arrays

Problem:
I the sheet view only opens the first item in the arrays. I've looked and found a few similar answers, but they don't deal with zipping arrays together. They mostly have one array. Here is one example. I've also tried to extract the item to a string, and then use the string instead of the item.0, or item.1.
If anyone has any suggestions, it would help a lot.
Main Code:
ScheduledAirplanes = ["1", "2", "3", "4"]
ScheduledInstructors = ["5", "6", "7", "8"]
ScheduledstartTime = ["9", "10", "11", "12"]
ScheduledDate = ["1/2", "1/3", "1/4", "1/5"]
#State private var showingSheet = false
var arraysForLoop : [(String,String,String,String)] {
let result = zip(ScheduledAirplanes,zip(ScheduledInstructors,zip(ScheduledstartTime,ScheduledDate)))
return result.map { ($0.0, $0.1.0, $0.1.1.0, $0.1.1.1) }
}
ForEach(arraysForLoop, id: \.0) { item in
VStack {
Group {
Text("Time")
VStack {
Text(item.3)
.font(.caption)
.foregroundColor(.gray)
Text(item.2)
.font(.caption)
.foregroundColor(.gray)
}
.padding([.leading, .trailing])
Divider()
.padding([.leading, .trailing])
Text("Flight")
Text(item.0)
.font(.caption)
.foregroundColor(.gray)
Text("Instructor")
Text(item.1)
.font(.caption)
.foregroundColor(.gray)
}
}
.onTapGesture {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
FlightInfo(Airplane: "\(item.0)", Instructor: "\(item.1)")
}
.frame(width: 110, height: 140)
.overlay {
RoundedRectangle(cornerRadius: 10)
.stroke(.gray.opacity(0.3), lineWidth: 1)
}
Spacer()
}
Here is the FlightView code:
struct FlightInfo: View {
#Environment(\.dismiss) var dismiss
#State var Airplane: String
#State var Instructor: String
var body: some View {
VStack {
HStack {
Text("Flight Info")
.font(.title)
.fontWeight(.bold)
Spacer()
Button("Cancel") {
dismiss()
}
}
.padding()
VStack {
Text("\(Airplane)")
.font(.caption)
.fontWeight(.medium)
.foregroundColor(.gray)
Text("\(Instructor)")
.font(.caption)
.fontWeight(.medium)
.foregroundColor(.gray)
}
Spacer(minLength: 0)
Button(action: {
dismiss()
}) {
Text("Done")
}
.foregroundColor(.white)
.frame(width: 120, height: 45)
.background(Color("Blue"))
.cornerRadius(30)
.padding(.bottom)
}
}
}
I would strongly suggest that you rethink modeling your data by having a set of different String arrays that all correspond together by index. Instead, modeling your data with something like this would be much more friendly to work with in SwiftUI:
struct Model {
var scheduleAirplane : String
var scheduledInstructor: String
var scheduledStartTime: String
var scheduledDate: String
}
extension Model : Identifiable {
var id : String { scheduleAirplane }
}
If for some reason you're stuck with the separate arrays, you can still take advantage of the more friendly models by doing something like I have below. Note that I've kept your zip code and used to to create the models. The other important difference is that I'm using sheet(item:) and passing a reference to the correct item. That gets handled by a single sheet modifier that takes a reference to the item.
struct ContentView: View {
var scheduledAirplanes = ["1", "2", "3", "4"]
var scheduledInstructors = ["5", "6", "7", "8"]
var scheduledStartTime = ["9", "10", "11", "12"]
var scheduledDate = ["1/2", "1/3", "1/4", "1/5"]
#State private var sheetItem : Model?
var arraysForLoop : [Model] {
let result = zip(scheduledAirplanes,zip(scheduledInstructors,zip(scheduledStartTime,scheduledDate)))
return result.map { Model(scheduleAirplane: $0.0, scheduledInstructor: $0.1.0, scheduledStartTime: $0.1.1.0, scheduledDate: $0.1.1.1) }
}
var body: some View {
ForEach(arraysForLoop) { item in
VStack {
Group {
Text("Time")
VStack {
Text(item.scheduledDate)
.font(.caption)
.foregroundColor(.gray)
Text(item.scheduledStartTime)
.font(.caption)
.foregroundColor(.gray)
}
.padding([.leading, .trailing])
Divider()
.padding([.leading, .trailing])
Text("Flight")
Text(item.scheduleAirplane)
.font(.caption)
.foregroundColor(.gray)
Text("Instructor")
Text(item.scheduledInstructor)
.font(.caption)
.foregroundColor(.gray)
}
}
.onTapGesture {
sheetItem = item
}
.frame(width: 110, height: 140)
.overlay {
RoundedRectangle(cornerRadius: 10)
.stroke(.gray.opacity(0.3), lineWidth: 1)
}
Spacer()
}.sheet(item: $sheetItem) { item in
FlightInfo(Airplane: "\(item.scheduleAirplane)", Instructor: "\(item.scheduledInstructor)")
}
}
}
Note that if you took the first suggestion and coalesced the arrays into models first, the beginning of the View would just look like this:
struct ContentView: View {
var models = [Model]
#State private var sheetItem : Model?
var body: some View {
ForEach(models) { item in
//etc

Swift: Multiple Variables in ForEach Statement

Here is my code, and I'm wondering how can I allow all 4 arrays to be used in the ForEach statement as right now I can only use 2.
struct ContentView: View {
var array1 = ["1", "2", "3"]
var array2 = ["a", "b", "c"]
var array3 = ["!", "#", "#"]
var array4 = ["+", "-", "~"]
var body: some View {
VStack {
HStack {
Text("Upcoming Flights")
.font(.title2)
.fontWeight(.bold)
Spacer()
}
ScrollView(.horizontal) {
HStack {
ForEach(Array(zip(array1, array2)), id: \.0) { item in
VStack {
Group {
Text("Flight")
Text(item.0)
.padding(.bottom)
.font(.caption)
.foregroundColor(.gray)
Text("Instructor")
Text(item.1)
.font(.caption)
.foregroundColor(.gray)
}
}
.frame(width: 110, height: 140)
.overlay {
RoundedRectangle(cornerRadius: 10)
.stroke(.gray.opacity(0.3), lineWidth: 1)
}
Spacer()
}
}
.frame(height: 200)
}
.frame(height: 200)
.offset(y: -25)
}
.offset(y: -10)
.padding([.leading, .trailing, .bottom])
}
}
Thanks in advance. #jnpdx I hope this helps, and I made sure it was reproducible. I don't want the arrays combined, but set as Text, like the first two arrays all in the same Stack in the view.
With the way your data is currently structured, you could zip the arrays together into a multi-layered tuple and then extract the values. It's a little ugly.
struct ContentView: View {
var array1 = ["1", "2", "3"]
var array2 = ["a", "b", "c"]
var array3 = ["!", "#", "#"]
var array4 = ["+", "-", "~"]
var arraysForLoop : [(String,String,String,String)] {
let result = zip(array1,zip(array2,zip(array3,array4)))
return result.map { ($0.0, $0.1.0, $0.1.1.0, $0.1.1.1) }
}
var body: some View {
VStack {
HStack {
Text("Upcoming Flights")
.font(.title2)
.fontWeight(.bold)
Spacer()
}
ScrollView(.horizontal) {
HStack {
ForEach(arraysForLoop, id: \.0) { item in
VStack {
Group {
Text("Flight")
Text(item.0)
.padding(.bottom)
.font(.caption)
.foregroundColor(.gray)
Text("Instructor")
Text(item.1)
.font(.caption)
.foregroundColor(.gray)
Text(item.2)
Text(item.3)
}
}
.frame(width: 110, height: 140)
.overlay {
RoundedRectangle(cornerRadius: 10)
.stroke(.gray.opacity(0.3), lineWidth: 1)
}
Spacer()
}
}
.frame(height: 200)
}
.frame(height: 200)
.offset(y: -25)
}
.offset(y: -10)
.padding([.leading, .trailing, .bottom])
}
}
My suspicion is that long-term, you will decide that your current method of storing the data (eg multiple arrays of non-ID'd data) won't be an ideal structure. For instance, what if one array changes and the others don't? If the indexes change, all your data will be offset.
I'd recommend storing your data in one array where each item has each field you need (Instructor, Airplane, etc) -- this will make things much easier for you.

Change button/label text using key:value from local JSON - SwiftUI

New to SwiftUI. Trying to get a JSON key:value array to update to the next random item when the user presses the button. Got it to load up just fine, but the button does nothing. Tried making a shuffle function, but couldn't find a way to pass in the new values to the Text areas. Also tried to make my decodedQuotes and quote variables into #State vars inside the View, but they initialize before self is available.
Could normally call touchesBegan and write a simple function in Storyboard. Is there something similar I could do here?
var decodedQuotes = Bundle.main.decode([Quote].self, from: "quotes.json")
// parses an array with "quote":"name" pairs
var quote = decodedQuotes.randomElement()!
struct QuoteView: View {
var body: some View {
Button(action:
// Need it to update the Text below with a new random item from quote
)
HStack {
VStack {
HStack(alignment: .center) {
Text(quote.quote)
.multilineTextAlignment(.center)
.padding()
.foregroundColor(.black)
}
HStack {
Text("-\(quote.name)")
.foregroundColor(.black)
}
}
}
.frame(width: 300, height: 300, alignment: .center)
.background(Background(isHighlighted: true, shape: Rectangle()))
.foregroundColor(.blue)
.padding(4)
.cornerRadius(20)
}
}
You were on the right track with #State
struct Quote {
var quote : String
var name : String
}
var decodedQuotes = [Quote(quote: "test1", name: "name1"),
Quote(quote: "test2", name: "name2"),
Quote(quote: "test3", name: "name3"),]
struct QuoteView: View {
#State var quote : Quote? = decodedQuotes.randomElement()
var body: some View {
Button(action: {
quote = decodedQuotes.randomElement()
}) {
Text("New quote")
}
if let quote = quote {
HStack {
VStack {
HStack(alignment: .center) {
Text(quote.name)
.multilineTextAlignment(.center)
.padding()
.foregroundColor(.black)
}
HStack {
Text("-\(quote.name)")
.foregroundColor(.black)
}
}
}
.frame(width: 300, height: 300, alignment: .center)
.foregroundColor(.blue)
.padding(4)
.cornerRadius(20)
}
}
}
Obviously, for testing, I just used an array of pre-made Quotes
If you wanted to, you could make decodedQuotes a #State property on the QuoteView as well and decode them in onAppear
I've also chosen to make quote an optional for now. I check to see if it's available by doing the if let quote = quote line. This should be a bit future-proof in case you start loading quotes from other places at some point.
I believe this is a better implementation in the current SwiftUI where the text actually changes within the button. I hope it helps>
import SwiftUI
struct Quote {
var quote : String
var name : String
}
var decodedQuotes = [Quote(quote: "Title 1", name: "Description 1."),
Quote(quote: "Title 2", name: "Second description."),
Quote(quote: "Title 3", name: "final item."),]
struct ContentView: View {
#State var quote : Quote? = decodedQuotes.randomElement()
var body: some View {
Button(action: {
quote = decodedQuotes.randomElement()
}) {
Text("New quote")
if let quote = quote {
HStack {
VStack {
VStack(alignment: .center) {
Text(quote.quote)
.multilineTextAlignment(.center)
.padding()
.foregroundColor(.blue)
Text("-\(quote.name)")
.foregroundColor(.blue)
}
}
}
.frame(width: 300, height: 300, alignment: .center)
.foregroundColor(.blue)
.padding(4)
.cornerRadius(20)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

SwiftUI - Interesting problem with binding array in list when deleting

This is a very similar problem to one I had before (which no one could answer). I'm trying to create a dynamic list in which I can edit elements. As far as I can gather, the recommended way to do this is to have an EditView, with bindings, that's activated by a NavigationLink in the LIst.
So, I've done that. It appears to work at first, until I realised that each NavigationLink would only work once (is this a bug?). I can't think what I could have done wrong to cause that.
Then I thought perhaps I can switch to in-place editing by having the EditView in the List. I devised a theoretical way to do this, then tried it in my code. And at first it seemed to work great. However, if 'edit in place' is on, deleting the last element causes 'Fatal error: Index out of range'.
I've bundled my whole code into one file so you can just copy and paste into Xcode to try for yourself.
I'm starting to think that maybe XCode 11.3.1 is far from the finished article, yet.
import SwiftUI
struct EditView: View {
#Binding var person:Person
var body: some View {
HStack{
Group{
TextField("name1", text: $person.name1)
TextField("name2", text: $person.name2)
}.frame(width:200)
.font(.headline)
.padding(.all, 3)
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.blue, lineWidth: 1))
}.navigationBarTitle("Edit entry")
}
}
struct Person:Identifiable, Equatable{
var id:UUID
var name1:String
var name2:String
var isEditable:Bool
}
class PersonList: ObservableObject {
#Published var individuals = [Person]()// Array of Person structs
}
struct ContentView: View {
#ObservedObject var people = PersonList()// people.individuals = [Person] array
#State private var edName1:String = "" //temporary storage for adding new member
#State private var edName2:String = "" //temporary storage for adding new member
#State private var allowEditing:Bool = false
var elementCount:Int{
let c = people.individuals.count
return c
}
// arrays for testing - adds random names from these (if input field '1st name' is empty)...
var firstNames = ["Nick","Hermes","John","Hattie","Nicola","Alan", "Dwight", "Richard","Turanga", "Don","Joey"]
var surnames = ["Farnsworth","Fry","Wong","Zoidberg","Conrad","McDougal","Power","Clampazzo","Brannigan","Kroker","Leela"]
var body: some View {
NavigationView{
VStack{
HStack{
Text("Add person:")
.padding(.all, 5)
.frame(alignment: .leading)
TextField("1st name", text: $edName1)
.frame(width:150)
.padding(.all, 5)
.overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.blue, lineWidth: 2))
TextField("2nd name", text: $edName2)
.frame(width:150)
.padding(.all, 5)
.overlay(RoundedRectangle(cornerRadius: 8)
.stroke(Color.blue, lineWidth: 2))
// 🆗 Button...
Image(systemName: "plus.circle")
.font(.largeTitle)
.foregroundColor(.orange)
.onTapGesture {
if self.edName1 == ""{
self.edName1 = self.firstNames.randomElement() ?? "⁉️"
self.edName2 = self.surnames.randomElement() ?? "⁉️"
}
self.people.individuals.append(Person(id: UUID(), name1: self.edName1, name2: self.edName2, isEditable: false))
self.edName1 = ""
self.edName2 = ""
print("Element count: \(self.elementCount)")
}
Toggle(isOn: $allowEditing){Text("edit in place")}.padding(.all,5).overlay(RoundedRectangle(cornerRadius: 8)
.stroke(Color.red, lineWidth: 2))
Spacer()
// 🆗 Button...sort
Image(systemName: "arrow.up.arrow.down.square")
.font(.title)
.padding(.all,4)
.foregroundColor(.blue)
.onTapGesture {
self.people.individuals.sort{ // sort list alphabetically by name2
$0.name2 < $1.name2
}
}
// 🆗 Button...reverse order
Image(systemName: "arrow.uturn.up.square")
.font(.title)
.padding(.all,8)
.foregroundColor(.blue)
.onTapGesture {
self.people.individuals.reverse()
}
}.padding(.all,8)
.overlay(RoundedRectangle(cornerRadius: 12)
.stroke(Color.orange, lineWidth: 2))
List{
ForEach(people.individuals){individual in
HStack{
if self.allowEditing{
//Toggle to edit in place
Toggle(isOn: self.$people.individuals[self.people.individuals.firstIndex(of:individual)!].isEditable){
Text("edit").font(.headline).foregroundColor(.green).opacity(individual.isEditable ? 1.0 : 0.4)
}.frame(width:100)
}
if individual.isEditable{
EditView(person: self.$people.individuals[self.people.individuals.firstIndex(of:individual)!])
}
else{
NavigationLink(destination:EditView(person: self.$people.individuals[self.people.individuals.firstIndex(of:individual)!])){
Text("\(individual.name1) \(individual.name2)")
.frame(width: 200, alignment: .leading)
.padding(.all, 3)
}// link
}
}
}.onDelete(perform: deleteRow)
}
}.navigationBarTitle("People List (\(elementCount))")
}.navigationViewStyle(StackNavigationViewStyle())
}
func deleteRow(at offsets: IndexSet){
self.people.individuals.remove(atOffsets: offsets)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environment(\.colorScheme, .dark)
}
}
Can anyone shed any light on this? I can't find anything to help me.
UPDATE: Thanks to 'krjw' for pointing out the single use NavLink problem does not happen on a real device.
The 'last element delete' issue seems to be something to do with an active binding being present in the element's view.
Ok despite my comment I tried to get to a solution and I might found an acceptable one:
I had to remodel Person... The whole indices was the issue of course but I couldn't exactly find out when what happens. I even tried with a local #State which updates the view and then updates the array of the #ObservedObject...
here are some links which could help to further investigate though...
Swift UI detail remove
How do I set the toggle state in a foreach loop in SwiftUI
Also this link here shows how to update members of an observed array generically which is pretty cool!:
https://stackoverflow.com/a/57920136/5981293
struct EditView: View {
#ObservedObject var person: Person
var body: some View {
HStack{
Group{
TextField("name1", text: $person.name1)
TextField("name2", text: $person.name2)
}//.frame(width:200)
.font(.headline)
.padding(.all, 3)
.overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.blue, lineWidth: 1))
}.navigationBarTitle("Edit entry")
}
}
struct RowView: View {
#Binding var allowEditing: Bool
#ObservedObject var individual: Person
var body: some View {
HStack {
if self.allowEditing {
//Toggle to edit in place
Toggle(isOn: self.$individual.isEditable){
Text("edit").font(.headline).foregroundColor(.green).opacity(self.individual.isEditable ? 1.0 : 0.4)
}//.frame(width:100)
}
if self.individual.isEditable{
EditView(person: self.individual)
}
else{
NavigationLink(destination:EditView(person: self.individual)){
Text("\(self.individual.name1) \(self.individual.name2)")
//.frame(width: 200, alignment: .leading)
.padding(.all, 3)
}// link
}
}
}
}
class Person: ObservableObject, Identifiable {
#Published var id:UUID
#Published var name1:String
#Published var name2:String
#Published var isEditable:Bool
init(id: UUID, name1: String, name2: String, isEditable: Bool){
self.id = id
self.name1 = name1
self.name2 = name2
self.isEditable = isEditable
}
}
struct ContentView: View {
#State var people = [Person]()//try! ObservableArray<Person>(array: []).observeChildrenChanges(Person.self)// people.individuals = [Person] array
#State private var edName1:String = "" //temporary storage for adding new member
#State private var edName2:String = "" //temporary storage for adding new member
#State private var allowEditing:Bool = false
// arrays for testing - adds random names from these (if input field '1st name' is empty)...
var firstNames = ["Nick","Hermes","John","Hattie","Nicola","Alan", "Dwight", "Richard","Turanga", "Don","Joey"]
var surnames = ["Farnsworth","Fry","Wong","Zoidberg","Conrad","McDougal","Power","Clampazzo","Brannigan","Kroker","Leela"]
var body: some View {
NavigationView{
VStack{
HStack{
Text("Add person:")
.padding(.all, 5)
.frame(alignment: .leading)
TextField("1st name", text: $edName1)
//.frame(width:150)
.padding(.all, 5)
.overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.blue, lineWidth: 2))
TextField("2nd name", text: $edName2)
//.frame(width:150)
.padding(.all, 5)
.overlay(RoundedRectangle(cornerRadius: 8)
.stroke(Color.blue, lineWidth: 2))
// 🆗 Button...
Image(systemName: "plus.circle")
.font(.largeTitle)
.foregroundColor(.orange)
.onTapGesture {
if self.edName1 == ""{
self.edName1 = self.firstNames.randomElement() ?? "⁉️"
self.edName2 = self.surnames.randomElement() ?? "⁉️"
}
self.people.append(Person(id: UUID(), name1: self.edName1, name2: self.edName2, isEditable: false))
self.edName1 = ""
self.edName2 = ""
print("Element count: \(self.people.count)")
}
Toggle(isOn: $allowEditing){Text("edit in place")}.padding(.all,5).overlay(RoundedRectangle(cornerRadius: 8)
.stroke(Color.red, lineWidth: 2))
Spacer()
// 🆗 Button...sort
Image(systemName: "arrow.up.arrow.down.square")
.font(.title)
.padding(.all,4)
.foregroundColor(.blue)
.onTapGesture {
self.people.sort{ // sort list alphabetically by name2
$0.name2 < $1.name2
}
}
// 🆗 Button...reverse order
Image(systemName: "arrow.uturn.up.square")
.font(.title)
.padding(.all,8)
.foregroundColor(.blue)
.onTapGesture {
self.people.reverse()
}
}.padding(.all,8)
.overlay(RoundedRectangle(cornerRadius: 12)
.stroke(Color.orange, lineWidth: 2))
List {
ForEach(self.people) { person in
RowView(allowEditing: self.$allowEditing, individual: person)
}.onDelete(perform: deleteRow)
}
}.navigationBarTitle("People List (\(self.people.count))")
}.navigationViewStyle(StackNavigationViewStyle())
}
func deleteRow(at offsets: IndexSet){
self.people.remove(atOffsets: offsets)
print(self.people.count)
}
}
I hope this helps!

Resources