Last active
March 22, 2018 12:48
-
-
Save jmcd/2499a901136df6f5c327216b27e4e6d4 to your computer and use it in GitHub Desktop.
Answer Playground for https://stackoverflow.com/questions/49309402/placing-labels-above-uislider-using-uistackview
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import PlaygroundSupport | |
class MySlider: UISlider { | |
// indent the tracking so the thumb does not hang outside the view | |
private let padding = CGFloat(18) | |
// the default rect for tracking is indented by a few pixels; keep note of that value here | |
private var trackIndent = CGFloat(0) | |
// how far the thumb is indented from the edge of the control; expose this so things outside the control can use it, e.g. laying out labels | |
var thumbIndent: CGFloat { return padding - trackIndent} | |
// take the default track-rect and pad it left and right, and keep note of the few pixels of base implementation indent in trackIndent | |
override func trackRect(forBounds bounds: CGRect) -> CGRect { | |
let superTrackRect = super.trackRect(forBounds: bounds) | |
trackIndent = superTrackRect.origin.x | |
return CGRect( | |
x: superTrackRect.origin.x + padding, | |
y: superTrackRect.origin.y, | |
width: superTrackRect.size.width - padding*2, | |
height: superTrackRect.size.height) | |
} | |
// take the default thumb-rect and allow it to overhang the left and right of the track-rect by half of its width | |
override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect { | |
let superThumbRect = super.thumbRect(forBounds: bounds, trackRect: rect, value: value) | |
let valueAsDecimalFraction = value == minimumValue ? 0 : (value - minimumValue)/(maximumValue - minimumValue) | |
let valueAsDecimalFractionOfMinusOneToOne = (valueAsDecimalFraction*2 - 1)/2 | |
let xOffset = CGFloat(valueAsDecimalFractionOfMinusOneToOne) * superThumbRect.width | |
return CGRect( | |
x: superThumbRect.origin.x + xOffset, | |
y: superThumbRect.origin.y, | |
width: superThumbRect.size.width, | |
height: superThumbRect.size.height) | |
} | |
} | |
class MyViewController : UIViewController { | |
static let range = 1...7 | |
let labels: [UILabel] = { | |
range.map { (i: Int) -> (UILabel) in | |
let l = UILabel() | |
l.text = "\(i)" | |
l.textAlignment = .center | |
return l | |
} | |
}() | |
let slider: MySlider = { | |
let s = MySlider() | |
s.minimumValue = Float(range.lowerBound) | |
s.maximumValue = Float(range.upperBound) | |
return s | |
}() | |
override func loadView() { | |
let view = UIView() | |
view.backgroundColor = .white | |
slider.backgroundColor = .orange | |
labels.forEach { $0.backgroundColor = .magenta } | |
let subviews: [UIView] = [slider] + labels | |
subviews.forEach { | |
$0.translatesAutoresizingMaskIntoConstraints = false | |
view.addSubview($0) | |
} | |
self.view = view | |
} | |
override func viewWillLayoutSubviews() { | |
let sliderConstraints = [ | |
slider.widthAnchor.constraint(equalTo: view.widthAnchor), | |
slider.centerYAnchor.constraint(equalTo: view.centerYAnchor), | |
] | |
let labelConstraints = labels.enumerated().map { (i, label) -> [NSLayoutConstraint] in | |
let pct = CGFloat(i)/CGFloat(labels.count-1) | |
let centerX = (view.bounds.size.width-2*self.slider.thumbIndent) * pct + self.slider.thumbIndent | |
return [ | |
label.centerXAnchor.constraint(equalTo: slider.leftAnchor, constant: centerX), | |
label.bottomAnchor.constraint(equalTo: slider.topAnchor, constant: 0), | |
] | |
}.flatMap { $0 } | |
view.removeConstraints(view.constraints) | |
(sliderConstraints + labelConstraints).forEach { | |
view.addConstraint($0) | |
$0.isActive = true | |
} | |
} | |
} | |
// Present the view controller in the Live View window | |
PlaygroundPage.current.liveView = MyViewController() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment