Search code examples
swiftrotationsliderconstraintstransform

constraint vertical slider on top anchor of another object


In my swift code there are 2 sliders 1 is on the bottom and 1 is constraint and rotate vertically. What I want to do is constraint the right slider to the top anchor of the bottom slider. You can see in the photo of what the current output and what I am looking for.

enter image description here

import UIKit

 class ViewController: UIViewController {


var bottomSlider = UISlider()
var rightSlider = UISlider()



override func viewDidLoad() {
    super.viewDidLoad()
    
    rightSlider.transform = CGAffineTransform(rotationAngle: .pi / 2)
   
    
    
    bottomSlider.value = 1
    [ bottomSlider, rightSlider].forEach {
        view.addSubview($0)
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.layer.borderWidth = 1
        $0.backgroundColor = UIColor(
            red: .random(in: 0.5...0.7),
            green: .random(in: 0.0...1),
            blue: .random(in: 0.3...0.5),
            alpha: 1
        )
        $0.layer.borderWidth = 1
        
        if let button = $0 as? UIButton {
            button.setTitleColor(.black, for: .normal)
        }
    }
    
    // Initialize sliderX's properties
    NSLayoutConstraint.activate([
        
        rightSlider.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -30),
        rightSlider.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor),
        rightSlider.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor),
       
        
        
        bottomSlider.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: -60),
        bottomSlider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.08),
        bottomSlider.widthAnchor.constraint(equalTo: view.widthAnchor),
        bottomSlider.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        
    
    ])
    
    bottomSlider.minimumValue = 1
    bottomSlider.maximumValue = 3
    
   
}


}

Solution

  • It would be more convenient to wrap the vertical slider into another UIView in this case. Then, you can position that UIView as you normally would.

    class VerticalSlider: UIView {
        let wrappedSlider = UISlider()
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            
            addSubview(wrappedSlider)
            wrappedSlider.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                wrappedSlider.centerXAnchor.constraint(equalTo: self.centerXAnchor),
                wrappedSlider.centerYAnchor.constraint(equalTo: self.centerYAnchor),
                // note the swapped width and height constraints here, because the slider is rotated
                wrappedSlider.widthAnchor.constraint(equalTo: self.heightAnchor),
                wrappedSlider.heightAnchor.constraint(equalTo: self.widthAnchor),
            ])
            wrappedSlider.transform = .init(rotationAngle: .pi / 2)
        }
        
        required init?(coder: NSCoder) {
            fatalError()
        }
    }
    

    Then you can position VerticalSlider like you normally would.

    class MyViewController: UIViewController {
    
        override func viewDidLoad() {
            let rightSlider = VerticalSlider()
            rightSlider.wrappedSlider.maximumValue = 1
            rightSlider.wrappedSlider.minimumValue = 0
            rightSlider.wrappedSlider.value = 0.5
            rightSlider.translatesAutoresizingMaskIntoConstraints = false
            
            let bottomSlider = UISlider()
            bottomSlider.maximumValue = 1
            bottomSlider.minimumValue = 0
            bottomSlider.value = 0.5
            bottomSlider.translatesAutoresizingMaskIntoConstraints = false
            
            view.addSubview(rightSlider)
            view.addSubview(bottomSlider)
            
            // note that I changed some of the constraints to use the safeAreaLayoutGuide of the view
            // you wouldn't want your sliders to go out of the safe area, would you?
            NSLayoutConstraint.activate([
                bottomSlider.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
                bottomSlider.heightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.08),
                bottomSlider.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor),
                bottomSlider.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
                
                rightSlider.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                rightSlider.bottomAnchor.constraint(equalTo: bottomSlider.topAnchor, constant: -8),
                rightSlider.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -30)
            ])
        }
    }
    

    Output (landscape mode, so that the screenshot doesn't appear too big):

    enter image description here