Slider .rotationEffect broken in MacOS 14.5

In a SwiftUI app for MacOS, vertical sliders that I'd created using a rotationEffect of 90° disappeared when I upgraded to Sonoma 14.5 (23F79). With rotations less than 90°, the slider is still visible, but its button is enlarged, growing in size as the rotation angle approaches 90°. Note that the sliders still work, even when rotated by 90° and invisible!

The screenshot and code below demonstrates the problem, which did not exist in MacOS 14.2.1


struct ContentView: View {
    @State var speed = CGFloat(1)
    
    var body: some View {
        HStack {
            let angle: [Double] = [0, 45, 80, 85, 90]
            ZStack {
                ForEach(0...4, id: \.self) { i in
                    ZStack () {
                        Rectangle()
                        Slider(value: $speed,
                               in: 0...10
                        )
                    }
                    .frame(width: 100, height: 10)
                    .rotationEffect(.degrees(angle[i]))
                    .offset(x: CGFloat(i * 100) - 180)
                }
            }
        }
        .padding()
        .frame(width: 600, height: 200)
    }
}

#Preview {
    ContentView()
}

The problem was not present in MacOS Ventura 13.6.7 and Xcode 15.2, as seen in this screenshot, using the same code, in which all the sliders have the correct appearance:

Testing on a clean installation of MacOS 14.4, with XCode 15.4, it's broken there in the same way as in MacOS 14.5, and in the beta of MacOS 15 as well.

Having the same problem on Sonoma 14.5 and Xcode 15.4 -- rotating 90 or 270 degrees fails to render the slider and console shows the message "CGAffineTransformInvert: singular matrix."

Yes, I hadn't noticed it before, but I'm seeing that error message too. That's probably a good clue as to what's broken under the hood. Do you also see the button (or "thumb") growing in size as the angle approaches 90°? That suggests that the rotationEffect is using the wrong matrix for any non-zero rotation, even though it only becomes singular at 90° (or multiple thereof). Oddly, other Shapes, like the Rectangles in my example, and even the center line of the Sliders, are rotated correctly, it's only the Slider's thumb that explodes.

@reindebock Yes, that's a good workaround for vertical sliders. Instead of including the whole SwiftUIIntrospect library, one can also just wrap the NSSlider in a NSViewRepresentable, (as that library presumably does under the hood, along the lines shown for iOS at https://swdevnotes.com/swift/2021/how-to-customise-the-slider-in-swiftui/#documentTop#use-uislider-from-uikit )

Here's a version of that for MacOS:

import SwiftUI

struct VerticalSlider: NSViewRepresentable {
    
    @Binding var value: Double
    var bounds: ClosedRange<Double>
       
    class Coordinator: NSObject {
        var value: Binding<Double>
        var bounds: ClosedRange<Double>
        
        init(value: Binding<Double>, bounds: ClosedRange<Double> = 0...1) {
            self.value = value
            self.bounds = bounds
        }
        
        @objc func valueChanged(_ sender: NSSlider) {
            self.value.wrappedValue = sender.doubleValue
        }
    }
    
    func makeCoordinator() -> VerticalSlider.Coordinator {
        Coordinator(value: $value)
    }
    
    func makeNSView(context: Context) -> NSSlider {
        let slider = NSSlider(frame: .zero)
        slider.isVertical = true
        
        slider.minValue = bounds.lowerBound
        slider.maxValue = bounds.upperBound
        slider.doubleValue = value
        slider.action = #selector(Coordinator.valueChanged(_:))
        slider.target = context.coordinator
        return slider
    }
    
    func updateNSView(_ nsView: NSSlider, context: Context) {
        nsView.doubleValue = value
    }
}

struct SliderTestView: View {
    @State var speed = 5.0

    var body: some View {
        VStack() {
            Text("\(speed)")
            
            VerticalSlider(value: $speed, bounds: 1.0...10.0)
                .onChange(of: speed) { speed in
                    print("\(speed)")
                }
                .frame(width: 50, height: 200)
        }
    }
}

#Preview {
    SliderTestView()
}
Slider .rotationEffect broken in MacOS 14.5
 
 
Q