NSView uses NSLayoutConstraint, and the transform set on the layer gets reset when the window size changes.


import Cocoa

class RedRotatedView: NSView {


    override func viewDidMoveToSuperview() {
        super.viewDidMoveToSuperview()

        DispatchQueue.main.async {
            self.applyRotation()
        }
    }


    private func applyRotation() {
        wantsLayer = true
        layer?.backgroundColor = NSColor.red.cgColor

        let radians = CGFloat(30 * Double.pi / 180.0)
        self.layer?.transform = CATransform3DMakeRotation(radians, 0, 0, 1)
    }

    override func layout() {
        super.layout()
    }
}

class MainView: NSView {
    let redView: RedRotatedView

    override init(frame frameRect: NSRect) {
        self.redView = RedRotatedView()
        super.init(frame: frameRect)
        setupRedView()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setupRedView() {
        redView.wantsLayer = true
        redView.layer?.backgroundColor = NSColor.red.cgColor
        addSubview(redView)


        redView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            redView.centerXAnchor.constraint(equalTo: centerXAnchor),
            redView.centerYAnchor.constraint(equalTo: centerYAnchor),
            redView.widthAnchor.constraint(equalToConstant: 200),
            redView.heightAnchor.constraint(equalToConstant: 200)
        ])
//        redView.frame = NSRect(x:100,y:100,width: 200,height: 200)


    }


}

@main
struct AppKitRotationTestApp {
    static func main() {
        let app = NSApplication.shared
        let delegate = AppDelegate()
        app.delegate = delegate
        app.run()
    }
}

class AppDelegate: NSObject, NSApplicationDelegate {
    var window: NSWindow!

    func applicationDidFinishLaunching(_ aNotification: Notification) {

        let mainView = MainView(frame: NSRect(x: 0, y: 0, width: 800, height: 600))

        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 800, height: 600),
            styleMask: [.titled, .closable, .resizable, .miniaturizable],
            backing: .buffered,
            defer: false
        )

        window.center()
        window.title = "AppKit Rotation Test"
        window.contentView = mainView
        window.makeKeyAndOrderFront(nil)
    }

    func applicationWillTerminate(_ aNotification: Notification) {

    }

    func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
        return true
    }
}

If NSLayoutConstraint is not used directly and the NSView's frame is set directly, this situation does not occur. How can I avoid the transform being reset when using NSLayoutConstraint for layout?

NSView uses NSLayoutConstraint, and the transform set on the layer gets reset when the window size changes.
 
 
Q