I am trying to make a group (10 in the test code, but 32 in reality) of vertical faders using SwiftUI on an iPad app. When making sliders horizontally, they stretch across the screen properly. When rotating those same sliders vertical, they seem locked into their horizontal dimensions. Is there a simple way to get the sliders to be vertical?
Horizontal (stretches across screen):
import SwiftUI
struct ContentView: View {
@State private var sliderVal: Double = 0
@State var values: [Double] = Array.init(repeating: 0.0, count: 10)
var body: some View {
VStack() {
ForEach((0 ... 9), id: \.self) {i in
HStack {
Text("\(i): ")
Slider(value: self.$values[i], in: 0 ... 100, step: 1.0)
.colorScheme(.dark)
Text("\(Int(self.values[i]))")
}
}
}
}
}
Switching the stack views and rotating the sliders (does not work):
struct ContentView: View {
@State private var sliderVal: Double = 0
@State var values: [Double] = Array.init(repeating: 0.0, count: 10)
var body: some View {
HStack() {
ForEach((0 ... 9), id: \.self) {i in
VStack {
Text("\(i): ")
Slider(value: self.$values[i], in: 0 ... 100, step: 1.0)
.colorScheme(.dark)
.rotationEffect(.degrees(-90))
Text("\(Int(self.values[i]))")
}
}
}
}
}
You can make vertical sliders from horizontal ones in SwiftUI, the trick is frame(width:) and frame(height:) are swapped. Here is what I did to make some really nice vertical sliders using the built-in SwiftUI functions
import SwiftUI
struct VerticalSlider: View {
@EnvironmentObject var playData : PlayData
var channelNumber:Int
var sliderHeight:CGFloat
var body: some View {
Slider(
value: self.$playData.flickerDimmerValues[self.channelNumber],
in: 0...255,
step: 5.0
).rotationEffect(.degrees(-90.0), anchor: .topLeading)
.frame(width: sliderHeight)
.offset(y: sliderHeight)
}
}
Then pass the Slider frame(width: ) to the above code in the variable sliderHeight as in the following code, where sliderHeight is the layout dimension provided by SwiftUI when it is laying out the view. This is a slick use of GeometryReader to size the slider exactly right.
import SwiftUI
struct VerticalBar: View {
@EnvironmentObject var playData : PlayData
var channelNumber:Int
var body: some View {
VStack {
GeometryReader { geo in
VerticalSlider(
channelNumber: self.channelNumber,
sliderHeight: geo.size.height
)
}
Text("\(self.channelNumber + 1)")
.font(.headline)
.frame(height: 10.0)
.padding(.bottom)
}
}
}
I then put 8 of the above views within a view area using a HStack:
HStack {
Spacer(minLength: 5.0)
VerticalBar(channelNumber: 0)
VerticalBar(channelNumber: 1)
VerticalBar(channelNumber: 2)
VerticalBar(channelNumber: 3)
VerticalBar(channelNumber: 4)
VerticalBar(channelNumber: 5)
VerticalBar(channelNumber: 6)
VerticalBar(channelNumber: 7)
Spacer(minLength: 5.0)
}
When completed, the vertical sliders look like this:
I made a custom VSlider view (source on GitHub) to address this issue. It should be virtually identical in usage to a Slider, as shown in the comparison demo below (although it's not generic, so it has to be used with a Double).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With