StackView UISlider

When I try to make a stackview that contains a view and a UISlider I can’t seem to move the UISlider. Is there a way to include the slider in a stackview? Or should I just avoid using it?

This is an image of my stackview there is supposed to be a green tint on the slider.

Screen Shot 2020-08-15 at 12.50.58 AM

Hi Bechir

Welcome to the Code Crew community.

Do you mean something like this?

Yeah but the thing is I need a width constraint on my view because thats what the slider is going to control. Is there a way to have it with that constraint?

@DoughOne

Just to be clear, are you wanting the slider to control the width of the view (the orange one in the example)?

@DoughOne

Hi Bechir,

Following on from my last post I have assumed that you want to control the coloured view width using the slider.
Yes you can do that.

In my example I have a slider and a view inside a vertical stack view. The stackView is set up with Alignment = Center and Distribution = Fill Equally. It has been centred vertically and horizontally in the parent view and constrained to the edges of the view with 20 points from the leading and trailing edges.

The Slider has been constrained to the edges of the stackView.

The only constraint on the orange view is a width constraint which in storyboard was an arbitrary value of 150. See the following image for the settings in the Document Outline

Outlets and Actions have been created as per the following screenshot.

  • The mySlider Outlet is there to be able to read the .value of the slider and set the minimumValue and maximumValue ranges.
    -The orangeViewWidth outlet is the connection to the NSLayoutConstraint.constant to control the width of that view.
  • The stackView outlet is to be able to read the width of the stackView frame in order to ensure that the change in width of the orange view does not exceed the stackView width.
  • The IBAction for the sliderMoved responds to the slider movement and adjusts the width of the orange view accordingly.

Hopefully the code is self explanatory.

And here is a video of the way it works.

Is there a way to make the width go back instead of get compressed down the middle?

I don’t understand what you mean.

I mean using the slider to make the view move one direction only instead of 2 when it gets bigger or smaller.

Hi Bechir,

In that case the constraint you use to adjust the width of the view would depend on which direction you want to make it grow or shrink.

For example if you wanted the leading edge to be fixed then the constraint that you would adjust under control of the slider would be the trailing edge constant.

I’m making the trailing constant adjustable with my slider but i can’t control it.

Screen Shot 2020-08-18 at 3.27.23 PM

@IBOutlet weak var slider: UISlider!


@IBOutlet weak var v: UIView!


@IBOutlet weak var vAdjust: NSLayoutConstraint!

@IBOutlet weak var s: UIStackView!


override func viewDidLoad() {
    super.viewDidLoad()
    vAdjust.constant = 0
    slider.value = 0
    slider.minimumValue = 0
    slider.maximumValue = Float(s.frame.width) + 1
}

@IBAction func sliderA(_ sender: Any) {
    vAdjust.constant = CGFloat(slider.value)
}

What you are adjusting is the value of the Constraint constant. In order to make the view smaller, ie the right edge move to the left, you make the constant value larger. So your calculation for the constraint value should be the width of the stackView frame minus the slider value.

@DoughOne

Did you get this part to work for you?

So it should be Float(s.frame.width) + 1 - CGFloat(Slider.value).

There is a couple of things to keep in mind.

  • The stackView.frame.width value is a CGFloat whereas
  • the slider.value is a Float

What you are doing it setting up your slider to be calibrated to the width of the stackView. So the minimum slider value would be 0 and the maximum would be Float(stackView.frame.width). Depending on the device size this will work because each device has a different screen resolution so by making the settings dynamic, they change according to the device the code is running on.

So in the case of the example attached I have the following set:

  • the slider.minimum value set to 0
  • the slider.maximum value set to the width of the stackView converting it to a Float value.
  • the slider initial value set to the stackView width divided by 2 (half way) and
  • the trailing edge constant set to the initial slider value (half way)

The IBAction sliderMoved() code simply sets that trailing edge according to the slider value. The way it does that is set the constraint constant (which is a CGFloat) to the width of the stackView minus the value of the slider. As the slider value increases the constraint constant decreases.

import UIKit

class ViewController: UIViewController {

    @IBOutlet var mySlider: UISlider!
    @IBOutlet var orangeViewTrailingEdge: NSLayoutConstraint!
    @IBOutlet var stackView: UIStackView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        mySlider.tintColor = .green
        
        //  Set up slider parameters
        mySlider.minimumValue = 0
        mySlider.maximumValue = Float(stackView.frame.width)
        mySlider.value = mySlider.maximumValue / 2
        orangeViewTrailingEdge.constant = CGFloat(mySlider.value)
    }

    @IBAction func sliderMoved(_ sender: Any) {
        orangeViewTrailingEdge.constant = CGFloat(mySlider.maximumValue) - CGFloat(mySlider.value)
    }
    
}

Video of the slider in action:

Okay I got it to work by using the trailing constant to the superview, but when I make
slider.value = Float(s.frame.width) / 2

I get the thumb of the slider at the beginning instead of at the middle and it shows the complete view instead of no view which it should at 0. If it was at half then half of the view should be shown.

I think the issue is i did not add a constraint or two.

Alright I set a trailing constant value manually in viewdidload and it works perfectly.