I am trying to get the position of the slider thumb to respond to changes coming from a TextField in another view through a common EnvironmentObject (inputs). The communication works fine from Slider to Inputs on to TextField. And the initial state of TextField is communicated to the Slider thumb through the .onAppear modifier and that works. So far so good. However, subsequent changes made in the TextField only show up in the Text view within the SliderView in the slider. Here's a screen shot of the inconsistent thumb position and text output
Notice the position of the thumb. It remains at position 4 which was its initial position.
I added a .onTapGesture to the Text view within the Slider and that works. Thumb moves to the position consistent with the input. Here is after the tap
I have been unable to find any modifier that will forces the thumb to respond to the change coming from the TextField. Since the .onTapGesture does work, I'm confident that the information is available to the slider, just can't get it to respond on it's own and the tapGesture solution seems klunky. I tried various modifiers All of the necessary code is below. It seems as if the change in the EnvironmentObject is not prompting the Slider to update.
//
// SliderExample.swift
// MapTests
//
// Created by Thomas Mead on 1/20/24.
//
import SwiftUI
import Foundation
struct SliderExample: View {
@EnvironmentObject var inputs : Inputs
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
VStack {
InputView()
SliderView()
}
}
}
struct InputView: View {
@EnvironmentObject var inputs: Inputs
var body: some View {
HStack {
Text("Sample Number")
TextField("SampleNumber", value: $inputs.sampleNumber, format: .number)
}
}
}
struct SliderView: View {
@EnvironmentObject var inputs: Inputs
@State var testNumber = 1.0
var body: some View {
HStack {
Slider(value: $testNumber, in: 1...20.0, step: 1.0)
.onChange(of: testNumber, perform: {data in inputs.sampleNumber = Int(testNumber)} )
.onAppear() {testNumber = Double(inputs.sampleNumber)}
Text("Sample \(Int(inputs.sampleNumber))")
.onTapGesture {
testNumber = Double(inputs.sampleNumber)
}
}
}
}
class Inputs: Observable, ObservableObject {
init() {
}
@Published var sampleNumber: Int = 4
}
#Preview {
SliderExample()
}
The reason your
Sliderdoes not update is because you do not update thetestNumberwhen thesampleNumberof the model changes.Try this approach using a
.onChange()in yourSliderViewNote, as mentioned, you should not have
Observableas well asObservableObjectin yourclass Inputs.Of course you can simplify your code by using
@Published var sampleNumber: Double = 4.0in yourInputs. Such as: