.onTapGesture Get Scrollview Item Data - uiscrollview

My full project is here https://github.com/m3rtkoksal/TaskManager
I have made SelectedTask an environment object as below
let context = persistentContainer.viewContext
let contentView = ContentView()
.environmentObject(observer())
.environmentObject(SelectedTask())
.environment(\.managedObjectContext,context)
In my TaskElement model I have created another class called SelectedTask as below
class SelectedTask: ObservableObject {
#Published var item = [TaskElement]()
func appendNewTask(task: TaskElement) {
objectWillChange.send()
item.append(TaskElement(title: task.title, dateFrom: task.dateFrom , dateTo: task.dateTo , text: task.text))
}
}
I am trying to fetch an item inside the scroll view and get its data to be able to modify it in the NewTaskView as below
struct ScrollViewTask: View {
#ObservedObject private var obser = observer()
#EnvironmentObject var selectedTask : SelectedTask
#State var shown: Bool = false
var body: some View {
ScrollView(.vertical) {
VStack {
ForEach(self.obser.tasks) { task in
TaskElementView(task:task)
.onTapGesture {
self.selectedTask.objectWillChange.send()
self.selectedTask.appendNewTask(task: task) //THREAD 1 ERROR
print(task)
self.shown.toggle()
}
}
}
}
.onAppear {
self.obser.fetchData()
}
.fullScreenCover(isPresented: $shown, content: {
NewTaskView(isShown: $shown)
.environmentObject(selectedTask)
})
}
}
But when I tap one of the items in scrollview I am getting a Thread 1 error #self.selectedTask.appendNewTask(task: task)
Thread 1: Fatal error: No ObservableObject of type SelectedTask found. A View.environmentObject(_:) for SelectedTask may be missing as an ancestor of this view.
If I change as ScrollViewTask().environmentObject(self.obser)
then this happens
This is how my TaskFrameView is called
import SwiftUI
struct TaskListView: View {
#State private(set) var data = ""
#State var isSettings: Bool = false
#State var isSaved: Bool = false
#State var shown: Bool = false
#State var selectedTask = TaskElement(title: "", dateFrom: "", dateTo: "", text: "")
var body: some View {
NavigationView {
ZStack {
Color(#colorLiteral(red: 0.9333333333, green: 0.9450980392, blue: 0.9882352941, alpha: 1)).edgesIgnoringSafeArea(.all)
VStack {
TopBar()
HStack {...}
CustomSegmentedView()
ZStack {
TaskFrameView() // scrollview inside
VStack {
Spacer()
HStack {...}
}
NavigationLink(
destination: NewTaskView(isShown: $shown).environmentObject(selectedTask),
isActive: $shown,
label: {
Text("")
})
}
}
}
.navigationBarHidden(true)
Spacer()
}
.navigationBarHidden(true)
}
}

It looks like the selectedTask is not injected to the TaskListView.
Find the place where you call TaskListView() and inject the selectedTask as an EnvironmentObject.
In ContentView:
struct ContentView: View {
#EnvironmentObject var selectedTask : SelectedTask
...
TaskListView().environmentObject(selectedTask)
Also don't create new instances of selectedTask like:
#State var selectedTask = TaskElement(title: "", dateFrom: "", dateTo: "", text: "")
Get the already created instance from the environment instead:
#EnvironmentObject var selectedTask: SelectedTask

call scroll view by sending the observer object as environment object modifier
ScrollViewTask().environmentObject(self. observer)

Related

SwiftUI presenting sheet with Binding variable doesn't work when first presented

I'm trying to present a View in a sheet with a #Binding String variable that just shows/binds this variable in a TextField.
In my main ContentView I have an Array of Strings which I display with a ForEach looping over the indices of the Array, showing a Button each with the text of the looped-over-element.
The Buttons action is simple: set an #State "index"-variable to the pressed Buttons' Element-index and show the sheet.
Here is my ContentView:
struct ContentView: View {
#State var array = ["first", "second", "third"]
#State var showIndex = 0
#State var showSheet = false
var body: some View {
VStack {
ForEach (0 ..< array.count, id:\.self) { i in
Button("\(array[i])") {
showIndex = i
showSheet = true
}
}
// Text("\(showIndex)") // if I uncomment this line, it works!
}
.sheet(isPresented: $showSheet, content: {
SheetView(text: $array[showIndex])
})
.padding()
}
}
And here is the SheetView:
struct SheetView: View {
#Binding var text: String
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
TextField("text:", text: $text)
Button("dismiss") {
presentationMode.wrappedValue.dismiss()
}
}.padding()
}
}
The problem is, when I first open the app and press on the "second" Button, the sheet opens and displays "first" in the TextField. I can then dismiss the Sheet and press the "second" Button again with the same result.
If I then press the "third" or "first" Button everything works from then on. Pressing any Button results in the correct behaviour.
Preview
Interestingly, if I uncomment the line with the Text showing the showIndex-variable, it works from the first time on.
Is this a bug, or am I doing something wrong here?
You should use custom Binding, custom Struct for solving the issue, it is complex issue. See the Example:
struct ContentView: View {
#State private var array: [String] = ["first", "second", "third"]
#State private var customStruct: CustomStruct?
var body: some View {
VStack {
ForEach (array.indices, id:\.self) { index in
Button(action: { customStruct = CustomStruct(int: index) }, label: {
Text(array[index]).frame(width: 100)
})
}
}
.frame(width: 300, height: 300, alignment: .center)
.background(Color.gray.opacity(0.5))
.sheet(item: $customStruct, content: { item in SheetView(text: Binding.init(get: { () -> String in return array[item.int] },
set: { (newValue) in array[item.int] = newValue }) ) })
}
}
struct CustomStruct: Identifiable {
let id: UUID = UUID()
var int: Int
}
struct SheetView: View {
#Binding var text: String
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
TextField("text:", text: $text)
Button("dismiss") {
presentationMode.wrappedValue.dismiss()
}
}.padding()
}
}
I had this happen to me before. I believe it is a bug, in that until it is used in the UI, it doesn't seem to get set in the ForEach. I fixed it essentially in the same way you did, with a bit of subtlety. Use it in each Button as part of the Label but hide it like so:
Button(action: {
showIndex = i
showSheet = true
}, label: {
HStack {
Text("\(array[i])")
Text(showIndex.description)
.hidden()
}
})
This doesn't change your UI, but you use it so it gets properly updated. I can't seem to find where I had the issue in my app, and I have changed the UI to get away from this, but I can't remember how I did it. I will update this if I can find it. This is a bit of a kludge, but it works.
Passing a binding to the index fix the issue like this
struct ContentView: View {
#State var array = ["First", "Second", "Third"]
#State var showIndex: Int = 0
#State var showSheet = false
var body: some View {
VStack {
ForEach (0 ..< array.count, id:\.self) { i in
Button(action:{
showIndex = i
showSheet.toggle()
})
{
Text("\(array[i])")
}.sheet(isPresented: $showSheet){
SheetView(text: $array, index: $showIndex)
}
}
}
.padding()
}
}
struct SheetView: View {
#Binding var text: [String]
#Binding var index: Int
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
TextField("text:", text: $text[index])
Button("dismiss") {
presentationMode.wrappedValue.dismiss()
}
}.padding()
}
}
In SwiftUI2 when calling isPresented if you don't pass bindings you're going to have some weird issues.
This is a simple tweak if you want to keep it with the isPresented and make it work but i would advise you to use the item with a costum struct like the answer of swiftPunk
This is how I would do it. You'll lose your form edits if you don't use #State variables.
This Code is Untested
struct SheetView: View {
#Binding var text: String
#State var draft: String
#Environment(\.presentationMode) var presentationMode
init(text: Binding<String>) {
self._text = text
self._draft = State(initialValue: text.wrappedValue)
}
var body: some View {
VStack {
TextField("text:", text: $draft)
Button("dismiss") {
text = draft
presentationMode.wrappedValue.dismiss()
}
}.padding()
}
}

SwiftUI Animation from #Published property changing from outside the View

SwiftUI offers .animation() on bindings that will animate changes in the view. But if an #Published property from an #ObserveredObject changes 'autonomously' (e.g., from a timer), while the view will update in response to the change, there is no obvious way to get the view to animate the change.
In the example below, when isOn is changed from the Toggle, it animates, but when changed from the Timer it does not. Interestingly, if I use a ternary conditional here rather than if/else even the toggle will not trigger animation.
struct ContentView: View {
#ObservedObject var model: Model
var body: some View {
VStack {
if model.isOn {
MyImage(color: .blue)
} else {
MyImage(color: .clear)
}
Spacer()
Toggle("switch", isOn: $model.isOn.animation(.easeIn(duration: 0.5)))
Spacer()
}
}
}
struct MyImage: View {
var color: Color
var body: some View {
Image(systemName: "pencil.circle.fill")
.resizable()
.frame(width: 100, height: 100)
.foregroundColor(color)
}
}
class Model: ObservableObject {
#Published var isOn: Bool = false
var timer = Timer()
init() {
timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { [unowned self] _ in
isOn.toggle()
})
}
}
How can I trigger animations when the value changes are not coming from a binding?
The easiest option is to add a withAnimation block inside your timer closure:
withAnimation(.easeIn(duration: 0.5)) {
isOn.toggle()
}
If you don't have the ability to change the #ObservableObject closure, you could add a local variable to mirror the changes:
struct ContentView: View {
#ObservedObject var model: Model
#State var localIsOn = false
var body: some View {
VStack {
if localIsOn {
MyImage(color: .blue)
} else {
MyImage(color: .clear)
}
Spacer()
Toggle("switch", isOn: $model.isOn.animation(.easeIn(duration: 0.5)))
Spacer()
}.onChange(of: model.isOn) { (on) in
withAnimation {
localIsOn = on
}
}
}
}
You could also do a similar trick with a mirrored variable inside your ObservableObject:
struct ContentView: View {
#ObservedObject var model: Model
var body: some View {
VStack {
if model.animatedOn {
MyImage(color: .blue)
} else {
MyImage(color: .clear)
}
Spacer()
Toggle("switch", isOn: $model.isOn.animation(.easeIn(duration: 0.5)))
Spacer()
}
}
}
class Model: ObservableObject {
#Published var isOn: Bool = false
#Published var animatedOn : Bool = false
var cancellable : AnyCancellable?
var timer = Timer()
init() {
timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { [unowned self] _ in
isOn.toggle()
})
cancellable = $isOn.sink(receiveValue: { (on) in
withAnimation {
self.animatedOn = on
}
})
}
}
You can use an implicit animation for that, i.e. .animation(_:value:), e.g.
struct ContentView: View {
#ObservedObject var model: Model
var body: some View {
VStack {
Group {
if model.isOn {
MyImage(color: .blue)
} else {
MyImage(color: .clear)
}
}
.animation(Animation.default, value: model.isOn)
}
}
}
withAnimation is called explicit.

why is a passed parameter displaying the previous content of an EnvironmentObject

this is a Macos app where the parsclass is setup in a previous view that contains the YardageRowView below. That previous view is responsible for changing the contents of the parsclass. This is working is other views that use a NavigationLink to display the views.
When the parsclass is changed, this view is refreshed, but the previous value is put in the text field on the holeValueTestView.
I cannot comprehend how the value is not being passed into the holeValueTestView correctly
This is a view shown as a .sheet, and if I dismiss it and display it again, everything is fine.
if you create a macOS project called YardageSample and replace the ContentView.swift and YardageSampleApp.swift with the two files below, you can see that the display in red changes and the black numbers do not change until you click Done and redisplay the .sheet
//
// YardageSampleApp.swift
// YardageSample
//
// Created by Brian Quick on 2021-04-12.
//
import SwiftUI
#main
struct YardageSampleApp: App {
#StateObject var parsclass = parsClass()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(parsclass)
}
}
}
//
// ContentView.swift
// YardageSample
//
// Created by Brian Quick on 2021-04-12.
//
import SwiftUI
struct ContentView: View {
#StateObject var parsclass = parsClass()
enum ActiveSheet : String , Identifiable {
case CourseMaintenance
var id: String {
return self.rawValue
}
}
#State var activeSheet : ActiveSheet? = nil
var body: some View {
Button(action: {
self.activeSheet = .CourseMaintenance
}) {
Text("Course Maintenance")
}
.sheet(item: $activeSheet) { sheet in
switch sheet {
case .CourseMaintenance:
CourseMaintenance()
}
}.frame(width: 200, height: 200, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
}
}
class parsClass: ObservableObject {
#Published var pars = [parsRec]()
init() {
self.pars = [parsRec]()
self.pars.append(parsRec())
}
func create(newpars: [parsRec]) {
pars.removeAll()
pars = newpars
}
}
class parsRec: Identifiable, Codable {
var id = UUID()
var Hole = 1
var Yardage = 1
}
struct CourseMaintenance: View {
#EnvironmentObject var parsclass: parsClass
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
Button(action: {presentationMode.wrappedValue.dismiss()}, label: {
Text("Done")
})
Button(action: {switchScores(number: 1)}, label: {
Text("Button 1")
})
Button(action: {switchScores(number: 2)}, label: {
Text("Button 2")
})
Button(action: {switchScores(number: 3)}, label: {
Text("Button 3")
})
CourseDetail().environmentObject(parsclass)
}.frame(width: 400, height: 400, alignment: .center)
}
func switchScores(number: Int) {
var newparRecs = [parsRec]()
for i in 0..<17 {
let myrec = parsRec()
myrec.Hole = i
myrec.Yardage = number
newparRecs.append(myrec)
}
parsclass.create(newpars: newparRecs)
}
}
struct CourseDetail: View {
#EnvironmentObject var parsclass: parsClass
var body: some View {
HStack(spacing: 0) {
ForEach(parsclass.pars.indices, id: \.self) { indice in
// this displays the previous value
holeValueTestView(value: String(parsclass.pars[indice].Yardage))
// this displays the correct value after parsclass has changed
Text(String(parsclass.pars[indice].Yardage))
.foregroundColor(.red)
}
}
}
}
struct holeValueTestView: View {
#State var value: String
var body: some View {
//TextField(String(value), text: $value)
Text(value)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
There are a couple of issues going on:
You have multiple instances of parsClass. One is defined in YardageSampleApp and passed into the view hierarchy as a #EnvironmentObject. The second is defined in ContentView as a #StateObject. Make sure you're only using one.
On holeValueTestView, you defined value as a #State variable. That gets set initially when the view is created by its parent and then it maintains its own state. So, when the environmentObject changed, because it was in charge of its own state at this point, it didn't update the value. You can simply remove #State and see the behavior that you want.
struct ContentView: View {
#EnvironmentObject var parsclass : parsClass //<-- Here
enum ActiveSheet : String , Identifiable {
case CourseMaintenance
var id: String {
return self.rawValue
}
}
#State var activeSheet : ActiveSheet? = nil
var body: some View {
Button(action: {
self.activeSheet = .CourseMaintenance
}) {
Text("Course Maintenance")
}
.sheet(item: $activeSheet) { sheet in
switch sheet {
case .CourseMaintenance:
CourseMaintenance()
}
}.frame(width: 200, height: 200, alignment: .center)
}
}
struct holeValueTestView: View {
var value: String //<-- Here
var body: some View {
Text(value)
}
}
As a side note:
In Swift, normally type names are capitalized. If you want to write idiomatic Swift, you would change your parsClass to ParsClass for example.

SwiftUI on macOS: list with detail view and multiple selection

TL;DR:
I cannot have a list with a detail view and multiple selections on macOS.
In more detail:
For demonstration purposes of my issue, I made a small example project. The UI looks as follows:
This is the "app" when launched, with a list on top and a detail representation below. Because I am using the List's initialiser init(_:selection:rowContent:), where selection is of type Binding<SelectionValue?>? according to Apple's documentation, I get selecting items with the keyboard arrow keys for free.
Here's the complete code:
import SwiftUI
#main
struct UseCurorsInLisstApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(ViewModel())
}
}
}
class ViewModel: ObservableObject {
#Published var items = [Item(), Item(), Item(), Item(), Item()]
#Published var selectedItem: Item? = nil
}
struct Item: Identifiable, Hashable {
let id = UUID()
}
struct ContentView: View {
#EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
List(vm.items, id: \.self, selection: $vm.selectedItem) { item in
VStack {
Text("Item \(item.id.uuidString)")
Divider()
}
}
Divider()
Group {
if let item = vm.selectedItem {
Text("Detail item \(item.id.uuidString)")
} else {
Text("No selection…")
}
}
.frame(minHeight: 200.0, maxHeight: .infinity)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Now, having had success with this so far, I figured being able to select more than one row would be useful, so I took a closer look into List(_:selection:rowContent:), where selection is of type Binding<Set<SelectionValue>>?. To be able to have a detail view, I just made a few minor changes to
the ViewModel:
class ViewModel: ObservableObject {
#Published var items = [Item(), Item(), Item(), Item(), Item()]
#Published var selectedItem: Item? = nil
#Published var selectedItems: Set<Item>? = nil {
didSet {
if selectedItems?.count == 1, let item = selectedItems?.first {
selectedItem = item
}
}
}
}
and the ContentView:
struct ContentView: View {
#EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
List(vm.items, id: \.self, selection: $vm.selectedItems) { item in
VStack {
Text("Item \(item.id.uuidString)")
Divider()
}
}
Divider()
Group {
if vm.selectedItems?.count == 1, let item = vm.selectedItems?.first {
Text("Detail item \(item.id.uuidString)")
} else {
Text("No or multiple selection…")
}
}
.frame(minHeight: 200.0, maxHeight: .infinity)
}
}
}
The problem now is that I cannot select an item of the row any more, neither by clicking, nor by arrow keys. Is this a limitation I am running into or am I "holding it wrong"?
Use the button and insert it into the set. Keyboard selection also works with shift + (up/down arrow)
class ViewModel: ObservableObject {
#Published var items = [Item(), Item(), Item(), Item(), Item()]
#Published var selectedItem: Item? = nil
#Published var selectedItems: Set<Item> = []
}
struct ContentView: View {
#EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
List(vm.items, id: \.self, selection: $vm.selectedItems) { item in
Button {
vm.selectedItem = item
vm.selectedItems.insert(item)
} label: {
VStack {
Text("Item \(item.id.uuidString)")
Divider()
}
}
.buttonStyle(PlainButtonStyle())
}
Divider()
Group {
if let item = vm.selectedItem {
Text("Detail item \(item.id.uuidString)")
} else {
Text("No or multiple selection…")
}
}
.frame(minHeight: 200.0, maxHeight: .infinity)
}
}
}
Add remove:
Button {
vm.selectedItem = item
if vm.selectedItems.contains(item) {
vm.selectedItems.remove(item)
} else {
vm.selectedItems.insert(item)
}
}
Edit
In simple need to give a blank default value to set. because in nil it will never append to set need initialization.
#Published var selectedItems: Set<Item> = [] {
Actually my error was pretty dumb – making the selectedItems-set optional prevents the list from working correctly. Shoutout to #Raja Kishan, who pushed me into the right direction with his proposal.
Here's the complete working code:
import SwiftUI
#main
struct UseCurorsInLisstApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(ViewModel())
}
}
}
class ViewModel: ObservableObject {
#Published var items = [Item(), Item(), Item(), Item(), Item()]
#Published var selectedItems = Set<Item>()
}
struct Item: Identifiable, Hashable {
let id = UUID()
}
struct ContentView: View {
#EnvironmentObject var vm: ViewModel
var body: some View {
VStack {
List(vm.items, id: \.self, selection: $vm.selectedItems) { item in
VStack {
Text("Item \(item.id.uuidString)")
Divider()
}
}
Divider()
Group {
if vm.selectedItems.count == 1, let item = vm.selectedItems.first {
Text("Detail item \(item.id.uuidString)")
} else {
Text("No or multiple selection…")
}
}
.frame(minHeight: 200.0, maxHeight: .infinity)
}
}
}

How to access value from an item in ForEach list

How to access values from particular item on the list made with ForEach?
As you can see I was trying something like this (and many other options):
Text(item[2].onOff ? "On" : "Off")
I wanted to check the value of toggle of 2nd list item (for example) and update text on the screen saying if it's on or off.
And I know that it's something to do with #Binding and I was searching examples of this and trying few things, but I cannot make it to work. Maybe it is a beginner question. I would appreciate if someone could help me.
My ContentView:
struct ContentView: View {
// #Binding var onOff : Bool
#State private var onOff = false
#State private var test = false
var body: some View {
NavigationView {
List {
HStack {
Text("Is 2nd item on or off? ")
Text(onOff ? "On" : "Off")
// Text(item[2].onOff ? "On" : "Off")
}
ForEach((1...15), id: \.self) {item in
ListItemView()
}
}
.navigationBarTitle(Text("List"))
}
}
}
And ListItemView:
import SwiftUI
struct ListItemView: View {
#State private var onOff : Bool = false
// #Binding var onOff : Bool
var body: some View {
HStack {
Text("99")
.font(.title)
Text("List item")
Spacer()
Toggle(isOn: self.$onOff) {
Text("Label")
}
.labelsHidden()
}
}
}
I don't know what exactly you would like to achieve, but I made you a working example:
struct ListItemView: View {
#ObservedObject var model: ListItemModel
var body: some View {
HStack {
Text("99")
.font(.title)
Text("List item")
Spacer()
Toggle(isOn: self.$model.switchedOnOff) {
Text("Label")
}
.labelsHidden()
}
}
}
class ListItemModel: ObservableObject {
#Published var switchedOnOff: Bool = false
}
struct ContentView: View {
#State private var onOff = false
#State private var test = false
#State private var list = [
(id: 0, model: ListItemModel()),
(id: 1, model: ListItemModel()),
(id: 2, model: ListItemModel()),
(id: 3, model: ListItemModel()),
(id: 4, model: ListItemModel())
]
var body: some View {
NavigationView {
List {
HStack {
Text("Is 2nd item on or off? ")
Text(onOff ? "On" : "Off")
// Text(item[2].onOff ? "On" : "Off")
}
ForEach(self.list, id: \.id) {item in
ListItemView(model: item.model)
}
}
.navigationBarTitle(Text("List"))
}.onReceive(self.list[1].model.$switchedOnOff, perform: { switchedOnOff_second_item in
self.onOff = switchedOnOff_second_item
})
}
}
The #Published basically creates a Publisher, which the UI can listen to per onReceive().
Play around with this and you will figure out what these things do!
Good luck :)
import SwiftUI
struct ContentView: View {
#State private var onOffList = Array(repeating: true, count: 15)
var body: some View {
NavigationView {
List {
HStack {
Text("Is 2nd item on or off? ")
Text(onOffList[1] ? "On" : "Off")
}
ForEach((onOffList.indices), id: \.self) {idx in
ListItemView(onOff: self.$onOffList[idx])
}
}
.navigationBarTitle(Text("List"))
}
}
}
struct ListItemView: View {
#Binding var onOff : Bool
var body: some View {
HStack {
Text("99")
.font(.title)
Text("List item")
Spacer()
Toggle(isOn: $onOff) {
Text("Label")
}
.labelsHidden()
}
}
}
I understand that you are directing me to use ObservableObject. And probably it's the best way to go with final product. But I am still thinking about #Binding as I just need to pass values better between 2 views only. Maybe I still don't understand binding, but I came to this solution.
struct ContentView: View {
// #Binding var onOff : Bool
#State private var onOff = false
// #State private var test = false
var body: some View {
NavigationView {
List {
HStack {
Text("Is 2nd item on or off? ")
Text(onOff ? "On" : "Off")
// Text(self.item[2].$onOff ? "On" : "Off")
// Text(item[2].onOff ? "On" : "Off")
}
ForEach((1...15), id: \.self) {item in
ListItemView(onOff: self.$onOff)
}
}
.navigationBarTitle(Text("List"))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
and ListItemView:
import SwiftUI
struct ListItemView: View {
// #State private var onOff : Bool = false
#Binding var onOff : Bool
var body: some View {
HStack {
Text("99")
.font(.title)
Text("List item")
Spacer()
Toggle(isOn: self.$onOff) {
Text("Label")
}
.labelsHidden()
}
}
}
What is happening now is text is being updated after I tap toggle. But I have 2 problems:
tapping 1 toggle changes all of them. I think it's because of this line:
ListItemView(onOff: self.$onOff)
I still cannot access value of just one row. In my understanding ForEach((1...15), id: .self) make each row have their own id, but I don't know how to access it later on.

Resources