I've searched and search SwiftUI Switch Case Menu Cycle? - swift

I've found great content, But nothing too specific to my needs being swiftui is still new.
I need to support menu cycling with switch case in the latest swift and monterey for macos, no ios development. i need strings, variables, and custom graphics to make a menu title and current in need of up to 9 menus to cycle randomly from one to a random other without an if statement looping through all of the others first:
more info here: https://pastebin.com/VCnEmdBa
Additional information on needs:
I want to have the switch case cycle my nine menus, where i can be on any given one and the menu jump to the next random selection, right now it currently rotates in order no matter where i click.
import Foundation
import SwiftUI
import CoreData
import Combine
import PDFKit
import SceneKit
import WebKit
struct Cotharticren: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct Option: Hashable {
let title: String
let imageName: String
}
struct ContentView: View {
#State var currentOption = 0
let options: [Option] = [
.init(title: "DART Meadow", imageName: "sun.max.fill"),
.init(title: "Research", imageName: "flame"),
.init(title: "Navigation", imageName: "moon.stars.fill"),
.init(title: "Shelf", imageName: "archivebox"),
.init(title: "Chest" ,imageName: "shippingbox"),
.init(title: "Crate" ,imageName: "bonjour"),
.init(title: "Manufactoring", imageName: "gear"),
.init(title: "Warehouse", imageName: "archivebox.fill"),
.init(title: "Journal", imageName: "note.text"),
]
var body: some View {
VStack(alignment: .leading) {
HStack(alignment: .top) {
ScrollView( .vertical) {
NavigationView{
/*
List(1..<9)
{
Text("\($0)")
}
.listStyle(SidebarListStyle())
}
*/
ListView(options: options, currentSelection: $currentOption)
//Text(systemName: myItem.selectedImageName) + Text(myItem.whateverText)
switch (currentOption) {
case 1:
OrbitNodeView()
case 2:
ATM26NodeView()
case 3:
NozzleNodeView()
case 4:
EmptyView()
VStack(alignment: .center) {
Text("Chest")
.font(.largeTitle)
.bold()
.colorInvert()
}
case 5:
EmptyView()
VStack(alignment: .center) {
Text("Crate")
.font(.largeTitle)
.bold()
.colorInvert()
}
case 6:
EmptyView()
VStack(alignment: .center) {
Text("Manufactoring")
.font(.largeTitle)
.bold()
.colorInvert()
}
case 7:
EmptyView()
VStack(alignment: .center) {
Text("Warehouse")
.font(.largeTitle)
.bold()
.colorInvert()
}
case 8:
VStack(alignment: .center) {
Text("Journal")
.font(.largeTitle)
.bold()
.colorInvert()
.padding(.top, 60)
Image("articrenmeadowopacity")
.shadow(radius: 3)
WebView()
}
default:
MainView()
}
}.background(Color.white)
}
}
}
Spacer()
}
}
struct MainView: View {
var body: some View{
VStack(alignment: .leading) {
HStack(alignment: .bottom) {
Image("CotharticrenMainView")
.shadow(radius: 3)
}
}
.frame(width: 900, height: 800, alignment: .center)
Spacer()
}
}
struct ListView: View {
let options: [Option]
#Binding var currentSelection: Int
var body: some View{
VStack(alignment: .leading) {
HStack(alignment: .top) {
HStack(alignment: .top) {
VStack(alignment: .trailing) {
Circle()
.stroke(Color.init(red: 0.9, green: 0.95, blue: 0.2, opacity: 1), lineWidth: 2)
.alignmentGuide(HorizontalAlignment.myAlignment)
{ d in d[.leading] }
.alignmentGuide(VerticalAlignment.myAlignment)
{ d in d[.bottom] }
.frame(width: 50, height: 50)
Circle()
.stroke(Color.init(red: 0.25, green: 0.9, blue: 0.2, opacity: 1), lineWidth: 2)
.alignmentGuide(HorizontalAlignment.myAlignment)
{ d in d[.leading] }
.alignmentGuide(VerticalAlignment.myAlignment)
{ d in d[.bottom] }
.frame(width: 25, height: 25)
VStack(alignment: .leading) {
Circle()
.stroke(Color.init(red: 0.1, green: 0.1, blue: 1, opacity: 1), lineWidth: 2)
.alignmentGuide(HorizontalAlignment.myAlignment)
{ d in d[.leading] }
.alignmentGuide(VerticalAlignment.myAlignment)
{ d in d[.bottom] }
.frame(width: 75, height: 75)
}
}
}
HStack(alignment: .top) {
Image("DARTMeadowCSMwidthArtemis2by1")
.shadow(radius: 3)
.padding(.top, 10)
}
.padding(.top, 20)
.padding(.trailing, 10)
}.padding(.top, 20).padding(.leading, 10)
HStack(alignment: .center) {
VStack(alignment: .center) {
Image("arrow300")
HStack(alignment: .center) {
Text("You've never plotted an Edge?")
}
}
}.shadow(radius: 3)
VStack(alignment: .leading) {
let current = options[currentSelection]
ForEach(options, id: \.self) {option in
HStack {
Image(systemName: option.imageName)
//.resizable()
//.aspectRatio(contentMode: .fit)
.frame(width: 20)
Text(option.title)
.foregroundColor(current == option ? Color.blue : Color.white)
}
.padding(8)
.onTapGesture {
currentSelection += 1
if currentSelection == 9 {
currentSelection = 0
}
}
}
Spacer()
}.frame(width: 300, height: 800, alignment: .leading)
}
Spacer()
}
}
struct WebView: View {
var body: some View{
VStack(alignment: .leading) {
HStack(alignment: .bottom) {
}
}
.frame(width: 900, height: 800, alignment: .center)
Spacer()
}
}

You can add an Identifier to your Option class and use this for currentSelection, if you want to set an option, just set currentSelection to option.id:
Also:
1: If you want answers, it's best to format your code, before you post it (select in Xcode and ctrl+i should do it), so it's easy to read and understand
2: A minimal, reproducible example is not just posting your entire code, create an example, that contains only as much code as necessary to show the problem you're experiencing. The code I posted would be a better example, it will work without having to change anything. Your code includes references to objects that are not on here, so a possible helper would have to remove those, before he could even test your issue
here is a guide on how to create a minimal, reproducible example:
struct Option: Hashable, Identifiable {
// Identifier for Option !! MUST be unique
let id: Int
let title: String
let imageName: String
}
struct ContentView: View {
#State var currentOption: Int = 0
let options: [Option] = [
.init(id: 1, title: "DART Meadow", imageName: "sun.max.fill"),
.init(id: 2, title: "Research", imageName: "flame"),
.init(id: 3, title: "Navigation", imageName: "moon.stars.fill"),
]
var body: some View {
GeometryReader { geo in
HStack {
ListView(options: options, currentSelection: $currentOption)
.frame(width: geo.size.width / 2, height: geo.size.height)
switch (currentOption) {
case 1: Text("OrbitNodeView")
case 2: Text("ATM26NodeView")
case 3: Text("NozzleNodeView")
default: Text("MainView")
}
}
}
}
}
struct ListView: View {
let options: [Option]
#Binding var currentSelection: Int
var body: some View{
VStack(alignment: .leading) {
ForEach(options, id: \.self) {option in
HStack {
Image(systemName: option.imageName)
.frame(width: 20)
Text(option.title)
// Don't even have to use current = options[currentSelection] anymore:
.foregroundColor(currentSelection == option.id ? .accentColor : .primary)
}
.padding(8)
.onTapGesture {
// Set the currentSelection to the ID of the option
currentSelection = option.id
}
}
}
}
}

Related

Construct View Like Pedantix SwiftUI

The problem is quite simple. I want to build something like Pedantix https://cemantix.certitudes.org/pedantix in SwiftUI.
I've this already :
So, I try to have my RoundedRectangle overlay to totally hide my text. And I want blocks to go at the line if needed, etc. I tried LazyHGrid (actually this), LazyVGrid, custom grid. But no results ...
import SwiftUI
struct Word: Identifiable, Equatable {
var id = UUID()
var text: String
var isFramed: Bool
var isTouched: Bool
}
struct ContentView: View {
#EnvironmentObject var service: Service
let rows = [
GridItem(.adaptive(minimum: 30)),
]
var body: some View {
GeometryReader { gr in
ScrollView {
VStack(alignment: .leading) {
HStack {
Spacer()
Image(systemName: "arrow.counterclockwise.circle")
.resizable()
.scaledToFit()
.frame(width: 24)
.onTapGesture {
service.loadRandomMovies(page: 1, completion: { _ in
service.loadMovie(id: service.randomMovieId ?? 0, completion: { _ in })
service.loadCredits(id: service.randomMovieId ?? 0, completion: { _ in })
})
}
}
HStack {
VStack {
RoundedRectangle(cornerRadius: 8)
.frame(width: 150, height: 250)
}
.padding()
VStack(alignment: .center) {
customTextView(with: service.frame(in: .title))
.padding(.bottom, 8)
customTextView(with: service.frame(in: .genres))
.padding(.bottom, 8)
.frame(width: gr.size.width * 0.8)
Text("\(service.movie?.releaseDate ?? "")")
.font(.title3)
.padding(.bottom, 8)
if service.movie?.tagline != "" {
Text("\"\(service.movie?.tagline ?? "")\"")
.font(.title3)
.padding(.bottom, 8)
.frame(alignment: .center)
}
customTextView(with: service.frame(in: .overview))
.padding(.bottom, 8)
.frame(width: gr.size.width * 0.8)
Text("\(service.credits?.cast.map({ $0.name }).joined(separator: " - ") ?? "")")
.fontWeight(.bold)
}
}
}
.padding()
}
.frame(width: gr.size.width)
}
}
}
extension ContentView {
#ViewBuilder
func customTextView(with words: [Word]) -> some View {
VStack {
LazyHGrid(rows: rows, spacing: 2) {
ForEach(words) { word -> AnyView in
if word.isFramed {
return AnyView(
Text("\(word.text)")
.padding(2)
.overlay(RoundedRectangle(cornerRadius: 4))
.overlay {
if word.isTouched {
Text("\(word.text.count)")
.foregroundColor(Color.cyan)
}
}
)
}
return AnyView(Text(word.text))
}
}
}
}
}
Do you think you could post your code so that we can see what you have done?

Swift, Stuck on making an notes app, don't know what the problem is using text editor

I am new to coding and am trying to make a notes app come to life, the issue is I have no idea how to make separate text editors in my for loops.
This is my code. When you run the project and create a green sticky note and type on it, it works fine, but if you do a second one of the same color, they have the same text. How do I fix this in a way that doesn't take hours of tedious work?
I have tried to use different ways to make a for loop. I have made one with normal lists and with a struct list that has different ids, both come up with the same text editor.
(Text editors don't copy over color, which makes me think it's the for loop because when I tried to use different variables for the bindings it didn't work either.)
//
// ContentView.swift
// Notesapp
//
//
import SwiftUI
import Foundation
struct newBoy: Identifiable {
let id = UUID()
let number: Int
}
class NewBoys: ObservableObject {
#Published var numbs = [newBoy]()
}
struct ContentView: View {
#StateObject var numbers1 = NewBoys()
#State var buttonoff = true
#State var recaddor: [GridItem] = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
]
#State var glist = [Int]()
#State var i = -1
#State var gtext = "This be me"
#State var blist = [Int]()
#State var bman = -1000
#State var btext = "Enter your notes here!"
#State var bklist = [Int]()
#State var bkman = -2000
#State var bktext = "Enter your notes here!"
#State var ylist = [Int]()
#State var yman = -3000
#State var ytext = "Enter your notes here!"
#State var olist = [Int]()
#State var oman = -4000
#State var otext = "Enter your notes here!"
#State var plist = [Int]()
#State var pman = -5000
#State var ptext = "Enter your notes here!"
var body: some View {
HStack{
VStack {
Text("Make new note!").padding().foregroundColor(Color.black)
Button {
withAnimation(.easeIn) {
self.buttonoff.toggle()
}
} label: {
Image(systemName: "plus")
.font(.title2)
.foregroundColor(.white)
.rotationEffect(.init(degrees: buttonoff ? 0 : 45))
.scaleEffect(buttonoff ? 1 : 1.3)
.padding()
}.buttonStyle(PlainButtonStyle())
.background(Color.black)
.clipShape(Circle())
.padding()
if buttonoff {
}
else {
Group {
Button {
recGreen()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.green)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recBlue()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.blue)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recBlack()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.black)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recYellow()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.yellow)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recOrange()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.orange)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
Button {
recPurple()
} label: {
RoundedRectangle(cornerRadius: 25)
.fill(Color.purple)
.frame(width: 30, height: 30)
}.buttonStyle(PlainButtonStyle())
}.padding(20)
.scaleEffect(1.5)
}
}.frame(width: 100, height: 700, alignment: .top)
.background(Color.white)
.border(Color.gray, width: 2)
VStack {
ScrollView{
LazyVGrid(columns: recaddor){
ForEach(numbers1.numbs, id: \.id) {o in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.green)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
print("hi")
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $gtext)
.frame(width: 225, height: 150, alignment: .center)
.cornerRadius(3.0)
.colorMultiply(.green)
Spacer()
}
}
}
ForEach(blist, id: \.self) {blueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.blue)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
blist = blist.filter({ Int in
return Int != blueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $btext)
Spacer()
}
}
}
ForEach(bklist, id: \.self) {bklueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.black)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
bklist = bklist.filter({ Int in
return Int != bklueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $bktext)
Spacer()
}
}
}
ForEach(ylist, id: \.self) {ylueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.yellow)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
ylist = ylist.filter({ Int in
return Int != ylueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $ytext)
Spacer()
}
}
}
ForEach(olist, id: \.self) {olueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.orange)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
olist = olist.filter({ Int in
return Int != olueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $otext)
Spacer()
}
}
}
ForEach(plist, id: \.self) {plueman in
ZStack{
RoundedRectangle(cornerRadius: 25)
.fill(Color.purple)
.frame(width: 250, height: 200)
.padding()
VStack{
HStack{
Spacer()
Button {
plist = plist.filter({ Int in
return Int != plueman
})
} label: {
Image(systemName: "minus")
}
.padding(.top, 25.0)
.padding(.trailing, 30.0)
.frame(alignment:.trailing)
}
TextEditor(text: $ptext)
Spacer()
}
}
}
}
}
}.frame(width: 1100)
}
}
func recGreen() {
let i = newBoy(number: 0)
numbers1.numbs.append(i)
print(numbers1.numbs)
}
func recBlue() {
bman += 1
blist.append(bman)
}
func recBlack() {
bkman += 1
bklist.append(bkman)
}
func recYellow() {
yman += 1
ylist.append(yman)
}
func recOrange() {
oman += 1
olist.append(oman)
}
func recPurple() {
pman += 1
plist.append(pman)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
It's because you are using the same binding.
In your ForEach, you are creating multiple TextEditors but they are editing the same variable like $otext. You need to create a struct that holds the text, and the array you use in the ForEach should be of type YourStruct. Then you pass the text to TextEditors.
struct Note: Identifiable {
var id: Int //your current array type, i.e if your array is [Int] use Int.
var text: String //this is the text to pass to the editors
}

Swift + Xcode + macOS: Non functional preview. Error is related to .environmentObject per Xcode

I am writing a Swift program and am trying to get one of the previews to work but with no luck. The error message I get is: Program crashed due to missing environment of type NavigationViewModel. To resolve add .envionmentObject(NavigationViewModel(...)) to the appropriate preview. I have tried several things with no luck. If anyone could point out my error it would be appreciated. Below is my code. The preview section is at the bottom.
Regards
Chris
import SwiftUI
struct ListView: View {
#EnvironmentObject var navVM: NavigationViewModel
var body: some View {
Spacer().frame(height: 30)
VStack {
ForEach (navVM.options, id: \.self) { option in
switch option.id {
case 0:
HomeItem(imageName: option.imageName, title: option.title, id: option.id)
case 1, 4, 7:
MainItem(imageName: option.imageName, title: option.title, id: option.id)
case 2, 3, 5, 6, 8, 9:
SubItem(title: option.title, id: option.id)
default:
Text("Something went wrong")
} // end switch
} // end for each
} // end vstack
Spacer()
.frame(width: 180, alignment: .leading)
} // end var body
} // end list view
struct HomeItem: View {
let imageName : String
let title : String
let id: Int
// let currentViewId: Int
#EnvironmentObject var navVM: NavigationViewModel
var body: some View {
HStack{
Image(systemName: imageName)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30, alignment: .leading)
.foregroundColor(navVM.highLightedImage == id ? Color.blue : Color.black)
.padding(.leading, 20 )
.padding(.top, 10)
Text(title)
.font(.system(size: 15))
.underline()
.frame(width: 125, alignment: .leading)
.foregroundColor(Color.blue)
.padding(.top, 15)
.onTapGesture {
navVM.updateCurrentViewId(value: id)
navVM.updateSelectedItem(value: 0)
navVM.updateHighLightedImage(value: 0)
}
} // end hstack
}
}
struct MainItem: View {
let imageName : String
let title : String
let id: Int
#EnvironmentObject var navVM: NavigationViewModel
var body: some View {
HStack{
Image(systemName: imageName)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 30, height: 30, alignment: .leading)
.foregroundColor(navVM.highLightedImage == id ? Color.blue : Color.black)
.padding(.leading, 20 )
.padding(.top, 10)
Text(title)
.font(.system(size: 15))
.frame(width: 125, alignment: .leading)
.padding(.top, 10)
} // end hstack
}
}
struct SubItem: View {
let title: String
// let currentViewId : Int
let id: Int
#EnvironmentObject var navVM: NavigationViewModel
var body: some View {
HStack{
Text(title)
.font(.system(size: 13))
.underline()
.frame(width: 35, alignment: .leading)
.foregroundColor(Color.blue)
.padding(.bottom, 2)
.padding(.leading, 15)
.onTapGesture {
navVM.updateCurrentViewId(value: id)
navVM.updateSelectedItem(value: id)
switch navVM.selecteditem {
case 2, 3:
navVM.updateHighLightedImage(value: 1)
case 5, 6:
navVM.updateHighLightedImage(value: 4)
case 8, 9:
navVM.updateHighLightedImage(value: 7)
default:
navVM.updateHighLightedImage(value: 0)
}
}
switch navVM.currentViewId {
case id:
Image(systemName: "checkmark").padding(.bottom, 5).foregroundColor(Color.blue).opacity(100)
default:
Image(systemName: "checkmark").padding(.bottom, 5).foregroundColor(Color.blue).opacity(0)
}
} // end hstack
}
}
struct ListView_Previews: PreviewProvider {
#EnvironmentObject var navVM: NavigationViewModel
static var previews: some View {
ListView()
}
// .environmentObject(navVM: NavigationViewModel())
}
Add it to the ListView() not the previews variable
ListView().environmentObject(navVM: NavigationViewModel())

ScrollView + Custom View + ContextMenu animation glitch - SwiftUI

Is there a workaround to fix these animation glitches? Glitch video
The animation glitch on scroll
The one where the view disappears for less than a second
The view semantics is:
TabView {
NavigationView {
ScrollView {
VStack {
ForEach(){
MyCustomView()
.contextMenu()
MyCustomView is below, if anyone would want to test it:
struct CardVew: View {
var title: String
var description: String
var name: String
var task: String
var done: Bool
let tapVibration = UIImpactFeedbackGenerator(style: .light)
#State var details = false
var body: some View {
ZStack(alignment: .leading) {
RoundedRectangle(cornerRadius: 15)
.foregroundColor(Color("cardGray"))
.opacity(0.24)
VStack(alignment: .leading, spacing: .zero) {
titleBlock
descriptionBlock
bottomBlock
}
.padding([.leading, .trailing], 20)
.padding(.bottom, 15)
.padding(.top, 24)
}
.padding([.leading, .trailing], 12)
.sheet(isPresented: $details) {
CardSheetView(
title: title,
description: description,
task: task,
name: name
)
}
.onTapGesture {
tapVibration.impactOccurred()
details = true
}
.onAppear {
tapVibration.prepare()
}
}
private var titleBlock: some View {
HStack(alignment: .top) {
Text(title)
.font(.system(size: 22, weight: .bold))
.fixedSize(horizontal: false, vertical: true)
.frame(width: 244, alignment: .leading)
.padding(.bottom, 4)
if done {
Spacer()
Image("done")
.opacity(0.8)
}
}
}
private var bottomBlock: some View {
HStack(alignment: .bottom) {
HStack(alignment: .center) {
Image(systemName: "calendar")
Text("22.09")
}
Spacer()
Text(name)
.multilineTextAlignment(.trailing)
.opacity(0.6)
.font(.footnote)
.frame(width: 211, alignment: .trailing)
}
}
private var descriptionBlock: some View {
Text(description)
.opacity(0.8)
.fixedSize(horizontal: false, vertical: true)
.frame(width: 247, alignment: .leading)
.padding(.bottom, 38)
}
}
i tried to exclude all animations, sheet and anything that could cause such behaviour, but had no success

Use data to define amount of objects in Array

I'm working on a checklist in SwiftUI and want to define the amount of checkboxes in my data. So for example, in case of fruit, the user should tick 3 checkboxes whereas water requires more checks because you need to drink more glasses of water a day.
I'm using "for each" in a HStack to make an array of checkboxes:
HStack {
ForEach(0 ..< 3) { index in
VStack {
Button(action: {
self.checked[index].toggle()
})
I want to replace the ( 0..<3) with checklist.steps which is where the amount (INT) is defined.
let checklistData = [
Checklist(title: "Fruit", instruction: "1 vakje = 1 stuk of 100g", steps: Int(4)),
Is there a way to define the amount of checkboxes in my data?
Thanks in advance <3
Solution
The following code worked for me:
HStack {
ForEach(0 ..< checklist.steps) { index in
VStack {
Button(action: {
self.checked[index].toggle()
})
i am not sure whether you want this?
HStack {
ForEach(0 ..< checklistData[x].steps) { index in
VStack {
Button(action: {
self.checked[index].toggle()
})
ok, here my better answer, thanks for your code:
struct ChecklistView: View {
var checklist: Checklist
#State var currentProgress: Float = 0.0
#State var checked = \[false, false, false, false\]
var body: some View {
ZStack(alignment: .leading) {
// RoundedRectangle(cornerRadius: 20)
// .foregroundColor(.red).opacity(0.5)
// .frame(width: 200)
VStack {
HStack(alignment: .top) {
checklist.image
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40, height: 40)
.padding(.trailing)
VStack(alignment: .leading) {
Text(checklist.title)
.font(.system(size: 16, weight: .medium))
.padding(.bottom, 4)
Text(checklist.instruction.uppercased()).font(.system(size: 12))
HStack {
ForEach(0 ..< checklist.steps) { index in
VStack {
Button(action: {
self.checked\[index\].toggle()
}) {
ZStack {
RoundedRectangle(cornerRadius: 8)
.foregroundColor(self.checked\[index\] ? Color("LightGreen") : .gray )
.frame(width: 40, height: 40)
Image(systemName: self.checked\[index\] ? "checkmark" : "plus")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 16, height: 16)
.foregroundColor(self.checked\[index\] ? .white : .white)
}
}
}
}
}
}
}.frame(width: 350, alignment: .leading)
}
}
.frame(width: 350)
.padding(.bottom, 16)
.cornerRadius(8)
.padding(.top, 20)
}
}
// MARK: data checklist
struct Checklist: Identifiable, Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(title)
}
var id = UUID().uuidString
var title: String
var instruction: String
var image: Image
var steps: Int
}
struct ContentView: View {
let checklistData = \[
Checklist(title: "Fruit", instruction: "1 vakje = 1 stuk of 100g", image: Image("kiwi"), steps: Int(4)),
Checklist(title: "Fruit", instruction: "1 vakje = 1 stuk of 100g", image: Image("kiwi"), steps: Int(2))
\]
var body: some View {
List(checklistData, id: \.self) { checkList in
ChecklistView(checklist: checkList)
}
}
}