Skip to content

Commit 9ea9ff8

Browse files
Merge pull request #5 from simformsolutions/feature/Dynamic_Spinner_Type_Enhancement
Feature/dynamic spinner type enhancement
2 parents 4d5abbc + 4726264 commit 9ea9ff8

File tree

10 files changed

+97
-48
lines changed

10 files changed

+97
-48
lines changed

SSSpinnerButton.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@
221221
);
222222
runOnlyForDeploymentPostprocessing = 0;
223223
shellPath = /bin/sh;
224-
shellScript = "if hash tailor 2>/dev/null; then\ntailor\nelse\necho \"warning: Please install Tailor from https://tailor.sh\"\nfi\n";
224+
shellScript = "if hash tailor 2>/dev/null; then\ntailor\nelse\necho \"warning: Please install Tailor from https://tailor.sh\"\nfi";
225225
};
226226
/* End PBXShellScriptBuildPhase section */
227227

SSSpinnerButton/Base.lproj/Main.storyboard

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
1919
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
2020
<subviews>
21-
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="L6t-dE-3h7">
22-
<rect key="frame" x="30" y="80" width="260" height="320"/>
21+
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="30" translatesAutoresizingMaskIntoConstraints="NO" id="L6t-dE-3h7">
22+
<rect key="frame" x="30" y="80" width="260" height="360"/>
2323
<subviews>
2424
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="UW4-Lx-QHw" customClass="SSSpinnerButton" customModule="SSSpinnerButton" customModuleProvider="target">
2525
<rect key="frame" x="0.0" y="0.0" width="260" height="40"/>
@@ -35,8 +35,11 @@
3535
</connections>
3636
</button>
3737
<button opaque="NO" tag="1" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oEx-V5-Ctm" customClass="SSSpinnerButton" customModule="SSSpinnerButton" customModuleProvider="target">
38-
<rect key="frame" x="0.0" y="70" width="260" height="40"/>
38+
<rect key="frame" x="0.0" y="70" width="260" height="80"/>
3939
<color key="backgroundColor" red="0.37647058823529411" green="0.90196078431372551" blue="0.82745098039215681" alpha="1" colorSpace="calibratedRGB"/>
40+
<constraints>
41+
<constraint firstAttribute="height" constant="80" id="oAt-2j-W9M"/>
42+
</constraints>
4043
<state key="normal" title="BallSpinFade">
4144
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
4245
</state>
@@ -45,8 +48,11 @@
4548
</connections>
4649
</button>
4750
<button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1bF-0X-zpK" customClass="SSSpinnerButton" customModule="SSSpinnerButton" customModuleProvider="target">
48-
<rect key="frame" x="0.0" y="140" width="260" height="40"/>
51+
<rect key="frame" x="0.0" y="180" width="260" height="40"/>
4952
<color key="backgroundColor" red="0.62352941176470589" green="0.72941176470588232" blue="0.99607843137254903" alpha="1" colorSpace="calibratedRGB"/>
53+
<constraints>
54+
<constraint firstAttribute="height" constant="40" id="Bff-R0-oeL"/>
55+
</constraints>
5056
<state key="normal" title="LineSpinFade">
5157
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
5258
</state>
@@ -55,8 +61,11 @@
5561
</connections>
5662
</button>
5763
<button opaque="NO" tag="3" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="znd-UY-1Sd" customClass="SSSpinnerButton" customModule="SSSpinnerButton" customModuleProvider="target">
58-
<rect key="frame" x="0.0" y="210" width="260" height="40"/>
64+
<rect key="frame" x="0.0" y="250" width="260" height="40"/>
5965
<color key="backgroundColor" red="0.84313725490196079" green="0.61176470588235299" blue="0.9137254901960784" alpha="1" colorSpace="calibratedRGB"/>
66+
<constraints>
67+
<constraint firstAttribute="height" constant="40" id="Efm-If-Dtj"/>
68+
</constraints>
6069
<state key="normal" title="BallRotateChase">
6170
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
6271
</state>
@@ -65,8 +74,11 @@
6574
</connections>
6675
</button>
6776
<button opaque="NO" tag="4" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Cbe-cO-clF" customClass="SSSpinnerButton" customModule="SSSpinnerButton" customModuleProvider="target">
68-
<rect key="frame" x="0.0" y="280" width="260" height="40"/>
77+
<rect key="frame" x="0.0" y="320" width="260" height="40"/>
6978
<color key="backgroundColor" red="1" green="0.78431372549019607" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/>
79+
<constraints>
80+
<constraint firstAttribute="height" constant="40" id="jDW-j4-0fJ"/>
81+
</constraints>
7082
<state key="normal" title="CircleStrokeSpin">
7183
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
7284
</state>

SSSpinnerButton/SSSpinnerButton/SpinerShapes/SpinnerAnimationDelegate/SpinnerAnimationDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ import UIKit
1111

1212
///
1313
protocol SSSpinnerAnimationDelegate {
14-
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor)
14+
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor, spinnerSize: UInt?)
1515
}

SSSpinnerButton/SSSpinnerButton/SpinerShapes/SpinnerShapeWithAnimation/SSBallRotateChase.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,35 @@ class SSBallRotateChase: SSSpinnerAnimationDelegate {
1717
/// - layer: layer Parent layer (Button layer)
1818
/// - frame: frame of parant layer
1919
/// - color: color of spinner
20-
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor) {
20+
/// - spinnerSize: size of spinner layer
21+
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) {
2122

22-
let defaultPadding: CGFloat = 10.0
23+
var defaultPadding: CGFloat = 10.0
24+
var sizeofSpinner: CGFloat?
25+
if spinnerSize != nil {
26+
defaultPadding = 0.0
27+
sizeofSpinner = max(CGFloat(spinnerSize!) - defaultPadding, 1.0)
28+
}
29+
var size = max(min(frame.width, frame.height) - defaultPadding, 1.0)
30+
if sizeofSpinner != nil && sizeofSpinner! > (size - defaultPadding) {
31+
defaultPadding = 10.0
32+
size = max(min(frame.width, frame.height) - defaultPadding, 1.0)
33+
sizeofSpinner = size
34+
}
2335

24-
let size = max(min(frame.width, frame.height) - defaultPadding, 1.0)
25-
let center = CGPoint(x: (size/2) + (defaultPadding / 2), y: (size/2) + (defaultPadding / 2))
26-
let circleSize = size / 6
36+
let center = CGPoint(x: (size/2) + (defaultPadding / 2), y: (size / 2) + (defaultPadding / 2))
37+
let circleSize = sizeofSpinner != nil ? max(min(sizeofSpinner! / 6, size / 6), 1.0) : size / 6
38+
2739
for i in 0 ..< 5 {
2840
let factor = Float(i) * 1 / 5
2941
let circle = SpinnerShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color)
30-
let animation = rotateAnimation(factor, x: center.x, y: center.y, size: CGSize(width: size - circleSize, height: size - circleSize))
42+
let animation = rotateAnimation(factor, x: center.x, y: center.y, size: CGSize(width: (sizeofSpinner != nil ? sizeofSpinner! : size) - circleSize, height: (sizeofSpinner != nil ? sizeofSpinner! : size) - circleSize))
3143

3244
circle.frame = CGRect(x: 0, y: 0, width: circleSize, height: circleSize)
3345
circle.add(animation, forKey: "animation")
3446
layer.addSublayer(circle)
3547
}
48+
3649
}
3750

3851

SSSpinnerButton/SSSpinnerButton/SpinerShapes/SpinnerShapeWithAnimation/SSBallSpinFadeLoader.swift

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@ class SSBallSpinFadeLoader: SSSpinnerAnimationDelegate {
1818
/// - layer: layer Parent layer (Button layer)
1919
/// - frame: frame of parant layer
2020
/// - color: color of spinner
21-
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor) {
21+
/// - spinnerSize: size of spinner layer
22+
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) {
2223

24+
let defaultPadding: CGFloat = 10.0
2325
let sizeValue = min(frame.width, frame.height)
24-
let center = CGPoint(x: (sizeValue/2.25), y: (sizeValue/2.25))
26+
var sizeOfSpinner = max(sizeValue - (defaultPadding), 1.0)
27+
if spinnerSize != nil {
28+
sizeOfSpinner = max(min(CGFloat(spinnerSize!), sizeOfSpinner), 1.0)
29+
}
30+
let center = CGPoint(x: (sizeValue / 2), y: (sizeValue / 2))
2531
let circleSpacing: CGFloat = 1
26-
let circleSize = (sizeValue * circleSpacing) / 8
32+
let circleSize = max((sizeOfSpinner * circleSpacing / 8), 1.0)
2733

2834
let duration: CFTimeInterval = 1
2935
let beginTime = CACurrentMediaTime()
@@ -56,7 +62,7 @@ class SSBallSpinFadeLoader: SSSpinnerAnimationDelegate {
5662
let circle = circleAt(angle: CGFloat(Double.pi / 4) * CGFloat(i),
5763
size: circleSize,
5864
origin: center,
59-
containerSize: CGSize(width: sizeValue, height: sizeValue),
65+
containerSize: CGSize(width: sizeOfSpinner, height: sizeOfSpinner),
6066
color: color)
6167

6268
animation.beginTime = beginTime + beginTimes[i]
@@ -77,11 +83,11 @@ class SSBallSpinFadeLoader: SSSpinnerAnimationDelegate {
7783
/// - color: spinner color
7884
/// - Returns:
7985
func circleAt(angle: CGFloat, size: CGFloat, origin: CGPoint, containerSize: CGSize, color: UIColor) -> CALayer {
80-
let radius = (containerSize.width / 2 - size / 2 ) - 4
86+
let radius = (containerSize.width / 2) - (size / 2)
8187
let circle = SpinnerShape.circle.layerWith(size: CGSize(width: size, height: size), color: color)
8288
let frame = CGRect(
83-
x: origin.x + radius * (cos(angle)),
84-
y: origin.y + radius * (sin(angle)),
89+
x: origin.x + radius * (cos(angle)) - (size / 2),
90+
y: origin.y + radius * (sin(angle)) - (size / 2),
8591
width: size,
8692
height: size)
8793

SSSpinnerButton/SSSpinnerButton/SpinerShapes/SpinnerShapeWithAnimation/SSCircleStrokeSpin.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,22 @@ import UIKit
1212
///
1313
class SSCircleStrokeSpin: SSSpinnerAnimationDelegate {
1414

15-
/// setup spinner layer
15+
/// setup spinner layer
1616
///
1717
/// - Parameters:
1818
/// - layer: layer Parent layer (Button layer)
1919
/// - frame: frame of parant layer
2020
/// - color: color of spinner
21-
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor) {
21+
/// - spinnerSize: size of spinner layer
22+
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) {
2223

2324
let defaultPadding: CGFloat = 10.0
24-
let sizeValue = max(min(frame.width, frame.height) - defaultPadding, 1.0)
25-
25+
var center = CGPoint(x: defaultPadding / 2, y: defaultPadding / 2)
26+
var sizeValue = max(min(frame.width, frame.height) - defaultPadding, 1.0)
27+
if spinnerSize != nil && CGFloat(spinnerSize!) < sizeValue {
28+
sizeValue = max(CGFloat(spinnerSize!), 1.0)
29+
center = CGPoint(x: frame.height / 2 - sizeValue / 2, y: frame.height / 2 - sizeValue / 2)
30+
}
2631
let beginTime: Double = 0.5
2732
let strokeStartDuration: Double = 1.2
2833
let strokeEndDuration: Double = 0.7
@@ -53,8 +58,8 @@ class SSCircleStrokeSpin: SSSpinnerAnimationDelegate {
5358

5459
let circle = SpinnerShape.stroke.layerWith(size: CGSize(width: sizeValue, height: sizeValue), color: color)
5560
let frame = CGRect(
56-
x: defaultPadding / 2,
57-
y: defaultPadding / 2,
61+
x: center.x,
62+
y: center.y,
5863
width: sizeValue,
5964
height: sizeValue
6065
)

SSSpinnerButton/SSSpinnerButton/SpinerShapes/SpinnerShapeWithAnimation/SSLineSpinFadeLoader.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ class SSLineSpinFadeLoader: SSSpinnerAnimationDelegate {
1818
/// - layer: layer Parent layer (Button layer)
1919
/// - frame: frame of parant layer
2020
/// - color: color of spinner
21-
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor) {
21+
/// - spinnerSize: size of spinner layer
22+
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) {
2223

2324
let defaultPadding: CGFloat = 4.0
2425

25-
let sizeValue = max(min(frame.width, frame.height) - defaultPadding, 1.0)
26-
let center = CGPoint(x: (sizeValue/2) + (defaultPadding / 2), y: (sizeValue/2) + (defaultPadding / 2))
26+
var sizeValue = max(min(frame.width, frame.height) - defaultPadding, 1.0)
27+
var center = CGPoint(x: (sizeValue / 2) + (defaultPadding / 2), y: (sizeValue/2) + (defaultPadding / 2))
28+
if spinnerSize != nil && CGFloat(spinnerSize!) < sizeValue {
29+
sizeValue = max(CGFloat(spinnerSize!), 1.0)
30+
center = CGPoint(x: frame.height / 2, y: frame.height / 2)
31+
}
2732
let duration: CFTimeInterval = 1.2
2833
let beginTime = CACurrentMediaTime()
2934
let beginTimes: [CFTimeInterval] = [0.12, 0.24, 0.36, 0.48, 0.6, 0.72, 0.84, 0.96]

SSSpinnerButton/SSSpinnerButton/SpinerShapes/SpinnerShapeWithAnimation/SSSpinnerBallClipRotate.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,25 @@ import UIKit
1212
///
1313
class SSSpinnerBallClipRotate: SSSpinnerAnimationDelegate {
1414

15-
/// setup spinner layer
15+
/// setup spinner layer
1616
///
1717
/// - Parameters:
1818
/// - layer: layer Parent layer (Button layer)
1919
/// - frame: frame of parant layer
2020
/// - color: color of spinner
21-
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor) {
21+
/// - spinnerSize: size of spinner layer
22+
func setupSpinnerAnimation(layer: CALayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) {
2223

23-
let sizeValue = min(frame.width, frame.height)
24-
24+
var sizeValue = min(frame.width, frame.height)
25+
var center = CGPoint(x: 0, y: 0)
26+
if spinnerSize != nil && CGFloat(spinnerSize!) < sizeValue {
27+
sizeValue = max(CGFloat(spinnerSize!), 1.0)
28+
center = CGPoint(x: frame.height / 2 - sizeValue / 2, y: frame.height / 2 - sizeValue / 2)
29+
}
2530
let ballClip = SpinnerShape.ring.layerWith(size: CGSize(width: sizeValue, height: sizeValue), color: color)
26-
ballClip.frame = CGRect(x: 0, y: 0, width: sizeValue, height: sizeValue)
31+
ballClip.frame = CGRect(x: center.x, y: center.x, width: sizeValue, height: sizeValue)
32+
ballClip.frame.size.height = sizeValue
33+
ballClip.frame.size.width = sizeValue
2734

2835
layer.addSublayer(ballClip)
2936

SSSpinnerButton/SSSpinnerButton/SpinnerButton/SSSpinnerButton.swift

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ open class SSSpinnerButton: UIButton {
4646
/// Sets the spinner color
4747
public var spinnerColor: UIColor = UIColor.gray
4848

49+
var spinnerSize: UInt?
4950
/// Sets the button title for its normal state
5051
public var title: String? {
5152
get {
@@ -135,8 +136,9 @@ public extension SSSpinnerButton {
135136
/// - Parameters:
136137
/// - spinnerType: spinner Type ( ballClipRotate(default), ballSpinFade, lineSpinFade, circleStrokeSpin, ballRotateChase)
137138
/// - spinnercolor: color of spinner (default = gray)
139+
/// - spinnerSize: size of spinner layer
138140
/// - complete: complation block (call after animation start)
139-
public func startAnimate(spinnerType: SpinnerType = .ballClipRotate, spinnercolor: UIColor = .gray, complete: (() -> Void)?) {
141+
public func startAnimate(spinnerType: SpinnerType = .ballClipRotate, spinnercolor: UIColor = .gray, spinnerSize: UInt?, complete: (() -> Void)?) {
140142
if self.cornrRadius == 0 {
141143
self.cornrRadius = self.layer.cornerRadius
142144
}
@@ -145,6 +147,7 @@ public extension SSSpinnerButton {
145147
isAnimating = true
146148
self.spinnerColor = spinnercolor
147149
self.spinnerType = spinnerType
150+
self.spinnerSize = spinnerSize
148151

149152
self.layer.cornerRadius = self.frame.height / 2
150153
self.collapseAnimation(complete: complete)
@@ -227,15 +230,14 @@ private extension SSSpinnerButton {
227230
self.setImage(storedHighlightedImage, for: .highlighted)
228231
isUserInteractionEnabled = true
229232

230-
let animaton = CABasicAnimation(keyPath: "bounds.size.width")
233+
let animation = CABasicAnimation(keyPath: "bounds.size.width")
234+
animation.fromValue = frame.height
235+
animation.toValue = frame.width
236+
animation.duration = animationDuration
237+
animation.fillMode = kCAFillModeForwards
238+
animation.isRemovedOnCompletion = false
231239

232-
animaton.fromValue = frame.height
233-
animaton.toValue = frame.width
234-
animaton.duration = animationDuration
235-
animaton.fillMode = kCAFillModeForwards
236-
animaton.isRemovedOnCompletion = false
237-
238-
layer.add(animaton, forKey: animaton.keyPath)
240+
layer.add(animation, forKey: animation.keyPath)
239241
isAnimating = false
240242
self.layer.cornerRadius = self.cornrRadius
241243
if complete != nil {
@@ -248,7 +250,7 @@ private extension SSSpinnerButton {
248250
@objc func startSpinner() {
249251

250252
let animation: SSSpinnerAnimationDelegate = self.spinnerType.animation()
251-
animation.setupSpinnerAnimation(layer: self.layer, frame: self.bounds, color: self.spinnerColor)
253+
animation.setupSpinnerAnimation(layer: self.layer, frame: self.bounds, color: self.spinnerColor, spinnerSize: self.spinnerSize)
252254
}
253255

254256
}

SSSpinnerButton/ViewController.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@ class ViewController: UIViewController {
3131

3232
let arr: [SpinnerType] = [.ballClipRotate, .ballSpinFade, .lineSpinFade, .ballRotateChase, .circleStrokeSpin]
3333

34-
sender.startAnimate(spinnerType: arr[sender.tag], spinnercolor: .white, complete: nil)
35-
36-
Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { (_) in
34+
sender.startAnimate(spinnerType: arr[sender.tag], spinnercolor: .white, spinnerSize: 20, complete: nil)
35+
Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { (_) in
3736
sender.stopAnimate(complete: {
3837
})
3938

0 commit comments

Comments
 (0)