Search code examples
swiftuislider

Vertical UISlider constraints


I am creating a vertical UISlider. I have created the view it is in using all code. (the rest of the storyboard elements are constrained using interface builder)

From what I have read, to create a vertical UISlider you give the UISlider a width and then rotate it. Since the height of the container that the UISlider sits in varies by screen size I do not want to give it a fixed height (width).

This is what I was thinking

    // Mark: Slider View

    let leftSlider = UISlider()
    let centerSlider = UISlider()
    let rightSlider = UISlider()

    let colorSliders = [leftSlider, centerSlider, rightSlider]

    for slider in colorSliders {

        slider.translatesAutoresizingMaskIntoConstraints = false
        sliderContainer.addSubview(slider)

        let w = sliderContainer.bounds.width
        slider.bounds.size.width = w
        slider.center = CGPoint(x: w/2, y: w/2)
        slider.transform = CGAffineTransform(rotationAngle: CGFloat(-M_PI_2))

        slider.value = 0
        slider.minimumValue = 0
        slider.maximumValue = 255

        let sliderTopConstraint = slider.topAnchor.constraint(equalTo: centerHiddenView.bottomAnchor, constant: 5)
        let sliderBottomConstraint = slider.bottomAnchor.constraint(equalTo: sliderContainer.bottomAnchor, constant: 5)

        NSLayoutConstraint.activate([sliderTopConstraint, sliderBottomConstraint])
        slider.backgroundColor = .purple
        slider.isEnabled = true
        slider.isUserInteractionEnabled = true

    }

    let sliderContainerWidth: CGFloat = sliderContainer.frame.width


    let centerSliderHorizontalConstraints = centerSlider.centerXAnchor.constraint(equalTo: sliderContainer.centerXAnchor)

    let widthConstraint = centerSlider.widthAnchor.constraint(equalToConstant: sliderContainerWidth)

    let centerSliderWidthConstraint = centerSlider.widthAnchor.constraint(equalToConstant: 90)

    NSLayoutConstraint.activate([centerSliderHorizontalConstraints, centerSliderWidthConstraint, widthConstraint])

But when I run it I get this

enter image description here

which is far better than what I had earlier today. However, I would like the slider to be normal width..and well look normal just vertical

Any ideas on what I missed? (Oh ignore that little purple offshoot to the left, that is the other 2 sliders that I added but didn't constrain yet.)


Solution

  • You're changing the bounds and the transform of your UISlider and are using Auto-Layout at the same time so it can be a little confusing.

    I suggest you don't modify the bounds but use Auto-Layout instead. You should set the slider width to its superview height, and center the slider inside its superview. This way, when you rotate it, its height (after rotation) which is actually its width (before rotation) will be equal to its superview height. Centering the slider vertically will make sure the slider is touching the bottom and the top of its superview.

    slider.widthAnchor.constraint(equalTo: sliderContainer.heightAnchor
    slider.centerYAnchor.constraint(equalTo: sliderContainer.centerYAnchor)
    
    slider.centerXAnchor.constraint(equalTo: sliderContainer.centerXAnchor)
    

    If you want to place one of the 2 remaining sliders to the left or right of their superview, don't center it horizontally but do the following instead:

    slider.leadingAnchor.constraint(equalTo: sliderContainer.leadingAnchor)
    
    slider.trailingAnchor.constraint(equalTo: sliderContainer.trailingAnchor)
    

    Also, carefully check your console for Auto-Layout error logs.

    EDIT: I checked the above code on a test project, here's my view controller code:

    class ViewController: UIViewController {
        @IBOutlet private weak var containerView: UIView!
    
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
            let leftSlider = UISlider()
            let centerSlider = UISlider()
            let rightSlider = UISlider()
            let colorSliders = [leftSlider, centerSlider, rightSlider]
    
            var constraints = [NSLayoutConstraint]()
            for slider in colorSliders {
                slider.translatesAutoresizingMaskIntoConstraints = false
                containerView.addSubview(slider)
    
                slider.transform = CGAffineTransform(rotationAngle: CGFloat(-M_PI_2))
    
                constraints.append(slider.widthAnchor.constraint(equalTo: containerView.heightAnchor))
                constraints.append(slider.centerYAnchor.constraint(equalTo: containerView.centerYAnchor))
    
                slider.backgroundColor = .purple
            }
            constraints.append(leftSlider.centerXAnchor.constraint(equalTo: containerView.centerXAnchor))
            constraints.append(centerSlider.centerXAnchor.constraint(equalTo: containerView.leadingAnchor))
            constraints.append(rightSlider.centerXAnchor.constraint(equalTo: containerView.trailingAnchor))
    
            NSLayoutConstraint.activate(constraints)
        }
    }
    

    And here's what I got: Test Project Result