Lawrence413
Lawrence413

Reputation: 2016

UISlider no subviews in ViewDidLoad()

I want to put a UILabel on the UISlider's thumb.

My code is based on this: Another SO question

The problem is that with that code, there's no text on the thumb before you change the value. So I made a few modifications. I made the label a global variable and I configure it in viewDidLoad(). Then I just change the text when the slider changes value.

The ACTUAL problem is this(code in viewDidLoad()):

let thumbView = mySlider.subviews.last
label.frame = (thumbView?.bounds)!

mySlider's subviews array is empty. Therefore it creates a crash since I unwrap a nil value.

I don't understand why that happens since the view is fully initialized.

Why is mySlider.subviews empty? What am I missing? Does anyone know how can I fix this? Is there any other way of placing the label in the middle of the thumb?

Upvotes: 1

Views: 773

Answers (3)

Saad Tahir
Saad Tahir

Reputation: 355

class ThumbTextSlider: UISlider {
 var thumbTextLabel: UILabel = UILabel()
 var passedValue = 0

 private var thumbFrame: CGRect {
     return thumbRect(forBounds: bounds, trackRect: trackRect(forBounds: 
  bounds), value: value)
 }

 override func layoutSubviews() {
     super.layoutSubviews()

     thumbTextLabel.frame = thumbFrame
     thumbTextLabel.text = String(passedValue)
 }

 override func awakeFromNib() {
     super.awakeFromNib()
     addSubview(thumbTextLabel)
     setThumbImage(#imageLiteral(resourceName: "icon-settings"), for: .normal)
     thumbTextLabel.font = UIFont(name: "SFProText-Semibold", size: 16)
     thumbTextLabel.textAlignment = .center
     thumbTextLabel.layer.zPosition = layer.zPosition + 1
 }
}

Upvotes: 0

Maxi Mus
Maxi Mus

Reputation: 815

The code from your linked question works fine, no need to change that.

Add this method and the initial value will appear as a UILabel on your UISlider:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    [mySlider sendActionsForControlEvents:UIControlEventValueChanged];
}

Upvotes: 0

Zac Kwan
Zac Kwan

Reputation: 5757

mySlider.subviews.last is not a reliable method to get the center of the thumbImage. It wasn't mention anywhere in the docs. I personally think is quite hacky to do it that way.

However, to get the center of the slider you could calculate base on the value of the slider using a combine of trackRectForBounds and thumbRectForBounds.

This should work for you:

@IBAction func sliderValueChanged(slider: UISlider) {
    let trackRect = slider.trackRectForBounds(slider.bounds)
    let thumbRect = slider.thumbRectForBounds(slider.bounds, trackRect: trackRect, value: slider.value)

    sliderLabel.center = CGPointMake(thumbRect.origin.x + thumbRect.size.width / 2 + slider.frame.origin.x, slider.frame.origin.y + thumbRect.size.height / 2)
}

Basically what this does is to first compute the rect of the track then use it to compute the thumbRect. Lastly set the center taking into consideration the width and height of the slider and thumb size.

Do remember to set your label text alignment to center.

Upvotes: 2

Related Questions