@@ -20,10 +20,9 @@ class SpringInterfaceViewController: InterfaceViewController {
2020
2121 private lazy var dampingSliderView : SliderView = {
2222 let sliderView = SliderView ( )
23- sliderView. translatesAutoresizingMaskIntoConstraints = false
24- sliderView. title = " DAMPING (BOUNCINESS) "
25- sliderView. minValue = 0.1
26- sliderView. maxValue = 1
23+ sliderView. valueFormatter = { String ( format: " %i%% " , Int ( $0 * 100 ) ) }
24+ sliderView. title = " DAMPING "
25+ sliderView. range = 0.1 ... 1
2726 sliderView. value = dampingRatio
2827 sliderView. sliderMovedAction = { self . dampingRatio = $0 }
2928 sliderView. sliderFinishedMovingAction = { self . resetAnimation ( ) }
@@ -32,10 +31,9 @@ class SpringInterfaceViewController: InterfaceViewController {
3231
3332 private lazy var frequencySliderView : SliderView = {
3433 let sliderView = SliderView ( )
35- sliderView. translatesAutoresizingMaskIntoConstraints = false
36- sliderView. title = " RESPONSE (SPEED) "
37- sliderView. minValue = 0.1
38- sliderView. maxValue = 2
34+ sliderView. valueFormatter = { String ( format: " %.2fs " , $0) }
35+ sliderView. title = " RESPONSE "
36+ sliderView. range = 0.1 ... 2
3937 sliderView. value = frequencyResponse
4038 sliderView. sliderMovedAction = { self . frequencyResponse = $0 }
4139 sliderView. sliderFinishedMovingAction = { self . resetAnimation ( ) }
@@ -46,26 +44,37 @@ class SpringInterfaceViewController: InterfaceViewController {
4644 private var frequencyResponse : CGFloat = 1
4745
4846 private let margin : CGFloat = 30
47+
48+ private var leadingAnchor , trailingAnchor : NSLayoutConstraint !
4949
5050 override func viewDidLoad( ) {
5151 super. viewDidLoad ( )
5252
5353 view. addSubview ( dampingSliderView)
54- dampingSliderView. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: margin) . isActive = true
55- dampingSliderView. trailingAnchor. constraint ( equalTo: view. trailingAnchor, constant: - margin) . isActive = true
56- dampingSliderView. centerYAnchor. constraint ( equalTo: view. centerYAnchor, constant: 0 ) . isActive = true
54+ UIView . activate ( constraints: [
55+ dampingSliderView. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: margin) ,
56+ dampingSliderView. trailingAnchor. constraint ( equalTo: view. trailingAnchor, constant: - margin) ,
57+ dampingSliderView. centerYAnchor. constraint ( equalTo: view. centerYAnchor, constant: 0 )
58+ ] )
5759
5860 view. addSubview ( frequencySliderView)
59- frequencySliderView. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: margin) . isActive = true
60- frequencySliderView. trailingAnchor. constraint ( equalTo: view. trailingAnchor, constant: - margin) . isActive = true
61- frequencySliderView. centerYAnchor. constraint ( equalTo: view. centerYAnchor, constant: 140 ) . isActive = true
61+ UIView . activate ( constraints: [
62+ frequencySliderView. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: margin) ,
63+ frequencySliderView. trailingAnchor. constraint ( equalTo: view. trailingAnchor, constant: - margin) ,
64+ frequencySliderView. centerYAnchor. constraint ( equalTo: view. centerYAnchor, constant: 140 )
65+ ] )
6266
6367 view. addSubview ( springView)
64- springView. heightAnchor. constraint ( equalToConstant: 80 ) . isActive = true
65- springView. widthAnchor. constraint ( equalToConstant: 80 ) . isActive = true
66- springView. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: margin) . isActive = true
67- springView. bottomAnchor. constraint ( equalTo: dampingSliderView. topAnchor, constant: - 80 ) . isActive = true
68-
68+ UIView . activate ( constraints: [
69+ springView. heightAnchor. constraint ( equalToConstant: 80 ) ,
70+ springView. widthAnchor. constraint ( equalToConstant: 80 ) ,
71+ springView. bottomAnchor. constraint ( equalTo: dampingSliderView. topAnchor, constant: - 80 )
72+ ] )
73+ self . leadingAnchor = springView. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: margin)
74+ self . leadingAnchor. isActive = true
75+ self . trailingAnchor = springView. trailingAnchor. constraint ( equalTo: view. trailingAnchor, constant: - margin)
76+ self . trailingAnchor. isActive = false
77+
6978 animateView ( )
7079
7180 }
@@ -74,22 +83,21 @@ class SpringInterfaceViewController: InterfaceViewController {
7483
7584 /// Repeatedly animates the view using the current `dampingRatio` and `frequencyResponse`.
7685 private func animateView( ) {
86+ self . view. layoutIfNeeded ( )
87+
7788 let timingParameters = UISpringTimingParameters ( damping: dampingRatio, response: frequencyResponse)
7889 animator = UIViewPropertyAnimator ( duration: 0 , timingParameters: timingParameters)
7990 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 ( )
91+ self . leadingAnchor. isActive = !self . leadingAnchor. isActive
92+ self . trailingAnchor. isActive = !self . trailingAnchor. isActive
93+ self . view. layoutIfNeeded ( )
8694 }
95+ animator. addCompletion { _ in self . animateView ( ) }
8796 animator. startAnimation ( )
8897 }
8998
9099 private func resetAnimation( ) {
91100 animator. stopAnimation ( true )
92- self . springView. transform = . identity
93101 animateView ( )
94102 }
95103
@@ -110,22 +118,20 @@ class SliderView: UIView {
110118 }
111119 set {
112120 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)
121+ valueLabel. text = valueFormatter ( newValue)
120122 }
121123 }
122124
123- public var maxValue : CGFloat = 1 {
125+ public var range : ClosedRange < Float > = 0 ... 1 {
124126 didSet {
125- slider. maximumValue = Float ( maxValue)
127+ slider. minimumValue = range. lowerBound
128+ slider. maximumValue = range. upperBound
126129 }
127130 }
128131
132+ /// Code to format the value to a string for the valueLabel
133+ public var valueFormatter : ( CGFloat ) -> ( String ) = { String ( format: " %.2f " , $0) }
134+
129135 /// Code that's executed when the slider moves.
130136 public var sliderMovedAction : ( CGFloat ) -> ( ) = { _ in }
131137
@@ -169,23 +175,29 @@ class SliderView: UIView {
169175 private func sharedInit( ) {
170176
171177 addSubview ( titleLabel)
172- titleLabel. leadingAnchor. constraint ( equalTo: leadingAnchor) . isActive = true
173- titleLabel. topAnchor. constraint ( equalTo: topAnchor) . isActive = true
178+ UIView . activate ( constraints: [
179+ titleLabel. leadingAnchor. constraint ( equalTo: leadingAnchor) ,
180+ titleLabel. topAnchor. constraint ( equalTo: topAnchor)
181+ ] )
174182
175183 addSubview ( valueLabel)
176- valueLabel. trailingAnchor. constraint ( equalTo: trailingAnchor) . isActive = true
177- valueLabel. lastBaselineAnchor. constraint ( equalTo: titleLabel. lastBaselineAnchor) . isActive = true
178-
184+ UIView . activate ( constraints: [
185+ valueLabel. trailingAnchor. constraint ( equalTo: trailingAnchor) ,
186+ valueLabel. lastBaselineAnchor. constraint ( equalTo: titleLabel. lastBaselineAnchor)
187+ ] )
188+
179189 addSubview ( slider)
180- slider. leadingAnchor. constraint ( equalTo: leadingAnchor) . isActive = true
181- slider. trailingAnchor. constraint ( equalTo: trailingAnchor) . isActive = true
182- slider. bottomAnchor. constraint ( equalTo: bottomAnchor) . isActive = true
183- slider. topAnchor. constraint ( equalTo: titleLabel. bottomAnchor, constant: 20 ) . isActive = true
184-
190+ UIView . activate ( constraints: [
191+ slider. leadingAnchor. constraint ( equalTo: leadingAnchor) ,
192+ slider. trailingAnchor. constraint ( equalTo: trailingAnchor) ,
193+ slider. bottomAnchor. constraint ( equalTo: bottomAnchor) ,
194+ slider. topAnchor. constraint ( equalTo: titleLabel. bottomAnchor, constant: 20 )
195+ ] )
196+
185197 }
186198
187199 @objc private func sliderMoved( slider: UISlider , event: UIEvent ) {
188- valueLabel. text = String ( format : " %.2f " , slider. value)
200+ valueLabel. text = valueFormatter ( CGFloat ( slider. value) )
189201 sliderMovedAction ( CGFloat ( slider. value) )
190202 if event. allTouches? . first? . phase == . ended { sliderFinishedMovingAction ( ) }
191203 }
0 commit comments