@@ -20,10 +20,10 @@ class SpringInterfaceViewController: InterfaceViewController {
2020
2121 private lazy var dampingSliderView : SliderView = {
2222 let sliderView = SliderView ( )
23+ sliderView. valueFormatter = { String ( format: " %i%% " , Int ( $0 * 100 ) ) }
2324 sliderView. translatesAutoresizingMaskIntoConstraints = false
24- sliderView. title = " DAMPING (BOUNCINESS) "
25- sliderView. minValue = 0.1
26- sliderView. maxValue = 1
25+ sliderView. title = " DAMPING "
26+ sliderView. range = 0.1 ... 1
2727 sliderView. value = dampingRatio
2828 sliderView. sliderMovedAction = { self . dampingRatio = $0 }
2929 sliderView. sliderFinishedMovingAction = { self . resetAnimation ( ) }
@@ -32,10 +32,10 @@ class SpringInterfaceViewController: InterfaceViewController {
3232
3333 private lazy var frequencySliderView : SliderView = {
3434 let sliderView = SliderView ( )
35+ sliderView. valueFormatter = { String ( format: " %.2fs " , $0) }
3536 sliderView. translatesAutoresizingMaskIntoConstraints = false
36- sliderView. title = " RESPONSE (SPEED) "
37- sliderView. minValue = 0.1
38- sliderView. maxValue = 2
37+ sliderView. title = " RESPONSE "
38+ sliderView. range = 0.1 ... 2
3939 sliderView. value = frequencyResponse
4040 sliderView. sliderMovedAction = { self . frequencyResponse = $0 }
4141 sliderView. sliderFinishedMovingAction = { self . resetAnimation ( ) }
@@ -46,6 +46,8 @@ class SpringInterfaceViewController: InterfaceViewController {
4646 private var frequencyResponse : CGFloat = 1
4747
4848 private let margin : CGFloat = 30
49+
50+ private var leadingAnchor , trailingAnchor : NSLayoutConstraint !
4951
5052 override func viewDidLoad( ) {
5153 super. viewDidLoad ( )
@@ -63,7 +65,10 @@ class SpringInterfaceViewController: InterfaceViewController {
6365 view. addSubview ( springView)
6466 springView. heightAnchor. constraint ( equalToConstant: 80 ) . isActive = true
6567 springView. widthAnchor. constraint ( equalToConstant: 80 ) . isActive = true
66- springView. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: margin) . isActive = true
68+ self . leadingAnchor = springView. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: margin)
69+ self . leadingAnchor. isActive = true
70+ self . trailingAnchor = springView. trailingAnchor. constraint ( equalTo: view. trailingAnchor, constant: - margin)
71+ self . trailingAnchor. isActive = false
6772 springView. bottomAnchor. constraint ( equalTo: dampingSliderView. topAnchor, constant: - 80 ) . isActive = true
6873
6974 animateView ( )
@@ -74,22 +79,21 @@ class SpringInterfaceViewController: InterfaceViewController {
7479
7580 /// Repeatedly animates the view using the current `dampingRatio` and `frequencyResponse`.
7681 private func animateView( ) {
82+ self . view. layoutIfNeeded ( )
83+
7784 let timingParameters = UISpringTimingParameters ( damping: dampingRatio, response: frequencyResponse)
7885 animator = UIViewPropertyAnimator ( duration: 0 , timingParameters: timingParameters)
7986 animator. addAnimations {
80- let translation = self . view. bounds. width - 2 * self . margin - 80
81- self . springView. transform = CGAffineTransform ( translationX: translation, y: 0 )
82- }
83- animator. addCompletion { _ in
84- self . springView. transform = . identity
85- self . animateView ( )
87+ self . leadingAnchor. isActive = !self . leadingAnchor. isActive
88+ self . trailingAnchor. isActive = !self . trailingAnchor. isActive
89+ self . view. layoutIfNeeded ( )
8690 }
91+ animator. addCompletion { _ in self . animateView ( ) }
8792 animator. startAnimation ( )
8893 }
8994
9095 private func resetAnimation( ) {
9196 animator. stopAnimation ( true )
92- self . springView. transform = . identity
9397 animateView ( )
9498 }
9599
@@ -110,22 +114,20 @@ class SliderView: UIView {
110114 }
111115 set {
112116 slider. value = Float ( newValue)
113- valueLabel. text = String ( format: " %.2f " , newValue)
114- }
115- }
116-
117- public var minValue : CGFloat = 0 {
118- didSet {
119- slider. minimumValue = Float ( minValue)
117+ valueLabel. text = valueFormatter ( newValue)
120118 }
121119 }
122120
123- public var maxValue : CGFloat = 1 {
121+ public var range : ClosedRange < Float > = 0 ... 1 {
124122 didSet {
125- slider. maximumValue = Float ( maxValue)
123+ slider. minimumValue = range. lowerBound
124+ slider. maximumValue = range. upperBound
126125 }
127126 }
128127
128+ /// Code to format the value to a string for the valueLabel
129+ public var valueFormatter : ( CGFloat ) -> ( String ) = { String ( format: " %.2f " , $0) }
130+
129131 /// Code that's executed when the slider moves.
130132 public var sliderMovedAction : ( CGFloat ) -> ( ) = { _ in }
131133
@@ -185,7 +187,7 @@ class SliderView: UIView {
185187 }
186188
187189 @objc private func sliderMoved( slider: UISlider , event: UIEvent ) {
188- valueLabel. text = String ( format : " %.2f " , slider. value)
190+ valueLabel. text = valueFormatter ( CGFloat ( slider. value) )
189191 sliderMovedAction ( CGFloat ( slider. value) )
190192 if event. allTouches? . first? . phase == . ended { sliderFinishedMovingAction ( ) }
191193 }
0 commit comments