I want to create a control pair similar to Logic Pro's fader: it's a Slider synchronized with a numeric TextTield. If you move the slider, the text field updates with the slider position, and if you enter something in the text field, the slider moves to a position corresponding to the new value. (Also the value gets used by the program logic but that's not the issue.)
I did this previously with AppKit and it works, and now I'm learning Swift and SwiftUI and I'm stuck.
Attached is my attempt at this. My "Fader" has clamps, so the setting will never be outside of a given range.
When I type a value in the TextField and hit the Slider updates as expected. The operation in the other direction doesn't work: when I move the Slider, the TextField doesn't update. I know the properties are updating because the print statements tell me so.
My code below has one @State property for the slider and another for the text field. I did this because if they shared the value property, the slider would move after each keypress in the text field, basically ignoring onSubmit. I found an example that used an ObservableObject class with one Published property and that property was used as the value: for both the slider and text field and that failed in the same was as my code.
What am I missing? Thanks in advance to anyone who can help.
struct SliderWithEditView: View {
private var rangeMin : Float = -100.0
private var rangeMax : Float = 100.0
@State private var textValue : Float
@State private var sliderValue : Float
/* accept default initializers */
init() {
textValue = rangeMin
sliderValue = rangeMin
}
/* user initializers from instantiation */
init(min : Float, max: Float) {
rangeMin = min
rangeMax = max
textValue = min
sliderValue = min
print("Starting values:\nrangeMin = \(rangeMin) to rangeMax = \(rangeMax)")
print("textValue = \(textValue)\tsliderValue = \(sliderValue)")
}
var body: some View {
VStack {
TextField("Value:",
value: $textValue,
format: .number.precision(.fractionLength(1)))
.frame(width: 50, height: 50)
.onSubmit {
print("New value = \(textValue)")
if textValue > rangeMax {
textValue = rangeMax
} else if textValue < rangeMin {
textValue = rangeMin
}
sliderValue = textValue
print("New slider value after text entry: \(sliderValue)")
}
.disableAutocorrection(true)
Slider(value: $sliderValue,
in: rangeMin...rangeMax,
step: 0.5,
onEditingChanged: { editing in
if editing == false {
textValue = sliderValue
print("After slide stops, sliderValue = \(sliderValue)\ttextValue = \(textValue)")
}
})
.frame(width: 200, height: 10)
.padding()
}
}
}
struct SliderWithEditView_Previews: PreviewProvider {
static var previews: some View {
SliderWithEditView()
}
}
Post
Replies
Boosts
Views
Activity
I developed a USB-MIDI device based on an embedded microcontroller. That all works well on both Mojave and Catalina. I configured my device to expose two IN ports and two OUT ports and they appear as expected in Audio MIDI Setup and various MIDI programs on the Mac talk to the device which responds appropriately.
I'm in the process of porting that design from the first micro to a new one (new family, new vendor device API, the whole works) and I've gotten as far as getting the device to enumerate. Mojave correctly shows the two IN and two OUT ports. Catalina, however, claims that my device has no ports. (The configuration descriptor completely defines the device's four ports.)
Wireshark's USB packet capture shows that after enumeration, both Mojave and Catalina send a SYSEX message to the device. What is the meaning of this message, and what response should I give?
I should note that I do see this message with my older (fully functioning) device, but I don't send any reply. It's possible that in Catalina, NAKs on the OUT endpoint are enough to say "no ports available" whereas earlier that didn't matter.