You’ve gotten two faucet gesture recognisers related to the identical ingredient, however solely one in every of these goes to fireplace.
You’ll want to remove one.
I’ve simplified your code to make use of a listing of attainable strings and a Set
of chosen strings however I feel it’s basically the identical as what you have got and it is best to be capable to apply it to your code.
The primary technique you can undertake is to take away the onTapGesture
from the Checkbox
and simply go away the one within the listing row. This requires that you just cross the isChecked
state in as an argument to Checkbox
:
struct ContentView: View {
@State var selectedItems: Set<String> = []
let gadgets = ["A","B","C"]
var physique: some View {
VStack {
Record {
ForEach(gadgets, id:.self) { merchandise in
HStack {
Textual content(merchandise)
Spacer()
Checkbox(isChecked: selectedItems.incorporates(merchandise))
.onTapGesture {
if self.selectedItems.incorporates(merchandise) {
self.selectedItems.take away(merchandise)
} else {
self.selectedItems.insert(merchandise)
}
}
}
}
}
Textual content("Chosen:")
Record {
ForEach(Array(self.selectedItems), id:.self) { merchandise in
Textual content(merchandise)
}
}
}
.padding()
}
}
struct Checkbox: View {
var isChecked: Bool
var physique: some View {
ZStack {
Rectangle()
.aspectRatio(1.0, contentMode: .match)
.foregroundStyle(Coloration.white)
.border(Coloration.black) //have to make thicker
.body(width: 30, top: 30)
if isChecked {
Picture(systemName: "checkmark")
}
}
}
}
As selectedItems
is a Set
, the incorporates
verify is environment friendly, though you’re in all probability coping with a small array so utilizing an array slightly than a set in all probability will not have a lot affect.
The opposite technique is to have the Checkbox
deal with the faucet itself, during which case the listing must cross in some code, by way of a closure, to be carried out within the faucet handler:
struct ContentView: View {
@State var selectedItems: Set<String> = []
let gadgets = ["A","B","C"]
var physique: some View {
VStack {
Record {
ForEach(gadgets, id:.self) { merchandise in
HStack {
Textual content(merchandise)
Spacer()
Checkbox(isChecked: selectedItems.incorporates(merchandise))
{ newValue in
if newValue {
self.selectedItems.insert(merchandise)
} else {
self.selectedItems.take away(merchandise)
}
}
}
}
}
Textual content("Chosen:")
Record {
ForEach(Array(self.selectedItems), id:.self) { merchandise in
Textual content(merchandise)
}
}
}
.padding()
}
}
struct Checkbox: View {
@State var isChecked: Bool
var motion: ((Bool)->Void)?
var physique: some View {
ZStack {
Rectangle()
.aspectRatio(1.0, contentMode: .match)
.foregroundStyle(Coloration.white)
.border(Coloration.black) //have to make thicker
.body(width: 30, top: 30)
.onTapGesture {
self.isChecked.toggle()
self.motion?(isChecked)
}
if isChecked {
Picture(systemName: "checkmark")
}
}
}
}
I in all probability want this second method because it separates the performance; The checkbox handles the faucet and updates its checked state. The listing row reacts to that modified state.
Word that even on this second implementation we nonetheless have to cross within the isChecked
worth to the Checkbox
in order that it might probably show accurately primarily based on the present state.