Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- Spruce (1.0)
- Spruce (1.0.0)

DEPENDENCIES:
- Spruce (from `../`)
Expand All @@ -9,7 +9,7 @@ EXTERNAL SOURCES:
:path: "../"

SPEC CHECKSUMS:
Spruce: ca7d637d19510fd5367de6a7bf64c3991deeaccf
Spruce: 71886861ff35a7c1980995faee12ed60895ec073

PODFILE CHECKSUM: '0682d1331d8ffa96d42f660fba6a53ca84d7b1ba'

Expand Down
5 changes: 3 additions & 2 deletions Example/Pods/Local Podspecs/Spruce.podspec.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Example/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

315 changes: 166 additions & 149 deletions Example/Pods/Pods.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class SpruceCollectionViewExample: ExampleViewController {
init(animations: [StockAnimation]) {
super.init(animations: animations, nibName: "SpruceCollectionViewExample")

sortFunction = CorneredSortFunction(corner: .topLeft, interObjectDelay: 0.05)
sortFunction = CorneredSortFunction(corner: .topLeft)
}

required init?(coder aDecoder: NSCoder) {
Expand Down
6 changes: 0 additions & 6 deletions Example/Spruce/ExampleCodeGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ class ExampleCodeGenerator {
sortFunctionString = String(format: sortFunctionFormatString,
string(forPosition: settings.position),
string(forDouble: settings.delay, decimals: 3))
case .continuous:
sortFunctionString = String(format: sortFunctionFormatString,
string(forPosition: settings.position),
string(forDouble: settings.duration))
case .weightedContinuous:
sortFunctionString = String(format: sortFunctionFormatString,
string(forPosition: settings.position),
Expand Down Expand Up @@ -67,8 +63,6 @@ class ExampleCodeGenerator {
return "RadialSortFunction(position: %@, interObjectDelay: %@)"
case .inline:
return "InlineSortFunction(corner: %@, interObjectDelay: %@)"
case .continuous:
return "ContinuousSortFunction(position: %@, duration: %@)"
case .weightedContinuous:
return "ContinuousWeightedSortFunction(position: %@, duration: %@, horizontalWeight: %@, verticalWeight: %@)"
case .random:
Expand Down
80 changes: 59 additions & 21 deletions Example/Spruce/SortFunctionTestViewController.storyboard

Large diffs are not rendered by default.

82 changes: 55 additions & 27 deletions Example/Spruce/SortFunctionTestViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ enum SortFunctions {
case cornered
case radial
case inline
case continuous
case weightedContinuous
case random

Expand All @@ -50,8 +49,6 @@ enum SortFunctions {
return "Radial"
case .inline:
return "Inline"
case .continuous:
return "Continuous"
case .weightedContinuous:
return "Weighted Continuous"
case .random:
Expand All @@ -74,6 +71,7 @@ class SortFunctionTestViewController: UIViewController {
@IBOutlet weak var directionControlView: UIView!
@IBOutlet weak var verticalWeightControlView: UIView!
@IBOutlet weak var horizontalWeightControlView: UIView!
@IBOutlet weak var timingFunctionControlView: UIView!

// Controls
@IBOutlet weak var durationSlider: UISlider!
Expand All @@ -92,7 +90,7 @@ class SortFunctionTestViewController: UIViewController {
@IBOutlet weak var sortView: UIView!

// Settings
let availableFunctions: [SortFunctions] = [.base, .linear, .cornered, .radial, .inline, .continuous, .weightedContinuous, .random]
let availableFunctions: [SortFunctions] = [.base, .linear, .cornered, .radial, .inline, .weightedContinuous, .random]
var settings = SortFunctionTestSettings()
var animationController: CustomAnimationViewController?

Expand Down Expand Up @@ -142,34 +140,36 @@ class SortFunctionTestViewController: UIViewController {
testController.setup()
animationController = testController

reloadControlViews()
let codeForFunction = ExampleCodeGenerator.generateCode(forSettings: settings)
print("\n\(codeForFunction)\n")
codeTextView.text = codeForFunction
}

func reloadControlViews() {
let activeControlViews = controlViewsForCurrentSettings()
for view in controlViews {
view.isHidden = !activeControlViews.contains(view)
}
let codeForFunction = ExampleCodeGenerator.generateCode(forSettings: settings)
print("\n\(codeForFunction)\n")
codeTextView.text = codeForFunction
}

func sortFunctionForCurrentSettings() -> SortFunction {
var sortFunction: SortFunction
switch settings.function {
case .base:
sortFunction = DefaultSortFunction(interObjectDelay: settings.delay)
sortFunction = DefaultSortFunction()
case .linear:
sortFunction = LinearSortFunction(direction: settings.direction, interObjectDelay: settings.delay)
sortFunction = LinearSortFunction(direction: settings.direction)
case .cornered:
sortFunction = CorneredSortFunction(corner: settings.corner, interObjectDelay: settings.delay)
sortFunction = CorneredSortFunction(corner: settings.corner)
case .radial:
sortFunction = RadialSortFunction(position: settings.position, interObjectDelay: settings.delay)
sortFunction = RadialSortFunction(position: settings.position)
case .inline:
sortFunction = InlineSortFunction(corner: settings.corner, interObjectDelay: settings.delay)
case .continuous:
sortFunction = ContinuousSortFunction(position: settings.position, duration: settings.duration)
sortFunction = InlineSortFunction(corner: settings.corner)
case .weightedContinuous:
sortFunction = ContinuousWeightedSortFunction(position: settings.position, duration: settings.duration, horizontalWeight: settings.horizontalWeight, verticalWeight: settings.verticalWeight)
sortFunction = WeightedSortFunction(position: settings.position, horizontalWeight: settings.horizontalWeight, verticalWeight: settings.verticalWeight)
case .random:
sortFunction = RandomSortFunction(interObjectDelay: settings.delay)
sortFunction = RandomSortFunction()
}

if var sortFunction = sortFunction as? DistanceSortFunction {
Expand All @@ -180,34 +180,46 @@ class SortFunctionTestViewController: UIViewController {
}

func controlViewsForCurrentSettings() -> [UIView] {

var timeView: UIView

switch settings.timingFunction {
case .total:
timeView = durationControlView
case .interItemTime:
timeView = delayControlView
default:
return []
}

switch settings.function {
case .base:
return [functionControlView, delayControlView]
return [functionControlView, timingFunctionControlView, timeView]
case .linear:
return [functionControlView, delayControlView, directionControlView, reverseControlView]
return [functionControlView, timingFunctionControlView, timeView, directionControlView, reverseControlView]
case .cornered:
return [functionControlView, delayControlView, cornerControlView, reverseControlView]
return [functionControlView, timingFunctionControlView, timeView, cornerControlView, reverseControlView]
case .radial:
return [functionControlView, delayControlView, positionControlView, reverseControlView]
return [functionControlView, timingFunctionControlView, timeView, positionControlView, reverseControlView]
case .inline:
return [functionControlView, delayControlView, cornerControlView, reverseControlView]
case .continuous:
return [functionControlView, durationControlView, positionControlView, reverseControlView]
return [functionControlView, timingFunctionControlView, timeView, cornerControlView, reverseControlView]
case .weightedContinuous:
return [functionControlView, durationControlView, positionControlView, horizontalWeightControlView, verticalWeightControlView, reverseControlView]
return [functionControlView, timingFunctionControlView, timeView, positionControlView, horizontalWeightControlView, verticalWeightControlView, reverseControlView]
case .random:
return [functionControlView, delayControlView]
return [functionControlView, timingFunctionControlView, timeView]
}
}

// Actions
@IBAction func durationDidChange(_ sender: UISlider) {
settings.duration = Double(sender.value)
settings.timingFunction = .total(TimeInterval(sender.value))
reloadSortView()
}

@IBAction func delayDidChange(_ sender: UISlider) {
settings.delay = Double(sender.value)
settings.timingFunction = .interItemTime(TimeInterval(sender.value))
reloadSortView()
}

Expand Down Expand Up @@ -301,6 +313,19 @@ class SortFunctionTestViewController: UIViewController {
settings.reverse = sender.isOn
reloadSortView()
}

@IBAction func timingFunctionDidChange(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
settings.timingFunction = .total(TimeInterval(settings.duration))
case 1:
settings.timingFunction = .interItemTime(TimeInterval(settings.delay))
default:
return
}

reloadSortView()
}
}

extension SortFunctionTestViewController {
Expand All @@ -317,7 +342,10 @@ extension SortFunctionTestViewController {
guard let sortFunction = self?.sortFunctionForCurrentSettings() else {
return
}
testController?.containerView?.spruce.animate(withSortFunction: sortFunction, animation: animation)
guard let settings = self?.settings else {
return
}
testController?.containerView?.spruce.animate(withSortFunction: sortFunction, duration: settings.timingFunction, animation: animation)
}
testController.customAnimation = animations
return testController
Expand Down Expand Up @@ -384,5 +412,5 @@ struct SortFunctionTestSettings {
var horizontalWeight: Weight = .light
var verticalWeight: Weight = .light
var reverse: Bool = false

var timingFunction: StockTimingFunction = .total(0.025)
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class SpruceTableViewControllerExample: ExampleViewController {
init(animations: [StockAnimation]) {
super.init(animations: animations, nibName: "SpruceTableViewControllerExample")

sortFunction = LinearSortFunction(direction: .topToBottom, interObjectDelay: 0.05)
sortFunction = LinearSortFunction(direction: .topToBottom)
}

required init?(coder aDecoder: NSCoder) {
Expand Down
16 changes: 8 additions & 8 deletions Sources/Classes/Full View/DefaultFullViewAnimations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public extension Spruce {
/// - animations: an array of stock animations
/// - duration: duration of each individual animation
/// - completion: a closure that is called upon the final animation completing. A `Bool` is passed into the closure letting you know if the animation has completed. **Note:** If you stop animations on the whole animating view, then `false` will be passed into the completion closure. However, if the final animation is allowed to proceed then `true` will be the value passed into the completion closure.
public func animate(_ animations: [StockAnimation], duration: TimeInterval = 0.3, completion: CompletionHandler? = nil ) {
let animation = StandardAnimation(duration: duration)
public func animate(_ animations: [StockAnimation], duration: StockTimingFunction = .interItemTime(0.1), completion: CompletionHandler? = nil ) {
let animation = StandardAnimation(duration: 0.3)
self.animate(animations, duration: duration, animationType: animation, completion: completion)
}

Expand All @@ -63,8 +63,8 @@ public extension Spruce {
/// - duration: duration of each individual animation
/// - sortFunction: the `sortFunction` to be used when setting the offsets for each subviews animation
/// - completion: a closure that is called upon the final animation completing. A `Bool` is passed into the closure letting you know if the animation has completed. **Note:** If you stop animations on the whole animating view, then `false` will be passed into the completion closure. However, if the final animation is allowed to proceed then `true` will be the value passed into the completion closure.
public func animate(_ animations: [StockAnimation], sortFunction: SortFunction, duration: TimeInterval = 0.3, completion: CompletionHandler? = nil ) {
let animation = StandardAnimation(duration: duration)
public func animate(_ animations: [StockAnimation], sortFunction: SortFunction, duration: StockTimingFunction = .interItemTime(0.1), completion: CompletionHandler? = nil ) {
let animation = StandardAnimation(duration: 0.3)
self.animate(animations, duration: duration, animationType: animation, sortFunction: sortFunction, completion: completion)
}

Expand All @@ -76,8 +76,8 @@ public extension Spruce {
/// - duration: duration of each individual animation
/// - animationType: style of animation that each view should follow. Don't worry about setting the `changeFunction`. We will set that using the stock animations that you provide. If you have a value there it will be overwritten. (ex: SpringAnimation)
/// - completion: a closure that is called upon the final animation completing. A `Bool` is passed into the closure letting you know if the animation has completed. **Note:** If you stop animations on the whole animating view, then `false` will be passed into the completion closure. However, if the final animation is allowed to proceed then `true` will be the value passed into the completion closure.
public func animate(_ animations: [StockAnimation], duration: TimeInterval = 0.3, animationType: Animation, completion: CompletionHandler? = nil) {
let sortFunction = LinearSortFunction(direction: .topToBottom, interObjectDelay: 0.05)
public func animate(_ animations: [StockAnimation], duration: StockTimingFunction = .interItemTime(0.1), animationType: Animation, completion: CompletionHandler? = nil) {
let sortFunction = LinearSortFunction(direction: .topToBottom)
self.animate(animations, duration: duration, animationType: animationType, sortFunction: sortFunction, completion: completion)
}

Expand All @@ -90,7 +90,7 @@ public extension Spruce {
/// - sortFunction: the `sortFunction` to be used when setting the offsets for each subviews animation
/// - prepare: a `bool` as to whether we should run `prepare` on your view for you. If set to `true`, then we will run `prepare` right before the animation using the stock animations that you provided. If `false`, then `prepare` will not run. (default is `true`)
/// - completion: a closure that is called upon the final animation completing. A `Bool` is passed into the closure letting you know if the animation has completed. **Note:** If you stop animations on the whole animating view, then `false` will be passed into the completion closure. However, if the final animation is allowed to proceed then `true` will be the value passed into the completion closure.
public func animate(_ animations: [StockAnimation], duration: TimeInterval = 0.3, animationType: Animation, sortFunction: SortFunction, prepare: Bool = true, completion: CompletionHandler? = nil) {
public func animate(_ animations: [StockAnimation], duration: StockTimingFunction = .interItemTime(0.1), animationType: Animation, sortFunction: SortFunction, prepare: Bool = true, completion: CompletionHandler? = nil) {

if prepare {
self.prepare(with: animations)
Expand All @@ -104,7 +104,7 @@ public extension Spruce {
animationFunc(view)
}
}
self.animate(withSortFunction: sortFunction, animation: animationType, completion: completion)
self.animate(withSortFunction: sortFunction, duration: duration, animation: animationType, completion: completion)
}

/// Use this method to setup all of your views before the animation occurs. This could include hiding, fading, translating them, etc...
Expand Down
5 changes: 3 additions & 2 deletions Sources/Classes/Full View/FullViewAnimation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ public extension Spruce {
/// - exclude: an array of views that the animation should skip over
/// - recursiveDepth: an int describing how deep into the view hiearchy the subview search should go, defaults to 0
/// - completion: a closure that is called upon the final animation completing. A `Bool` is passed into the closure letting you know if the animation has completed. **Note:** If you stop animations on the whole animating view, then `false` will be passed into the completion closure. However, if the final animation is allowed to proceed then `true` will be the value passed into the completion closure.
public func animate(withSortFunction sortFunction: SortFunction, prepare: PrepareHandler? = nil, animation: Animation, exclude: [UIView]? = nil, recursiveDepth: Int = 0, completion: CompletionHandler? = nil) {
var timedViews = sortFunction.timeOffsets(view: self.view, recursiveDepth: recursiveDepth)
public func animate(withSortFunction sortFunction: SortFunction, duration: StockTimingFunction, prepare: PrepareHandler? = nil, animation: Animation, exclude: [UIView]? = nil, recursiveDepth: Int = 0, completion: CompletionHandler? = nil) {
let weightedViews = sortFunction.weights(forView: self.view, recursiveDepth: recursiveDepth)
var timedViews = duration.timingFunction.timeOffsets(forViews: weightedViews)
timedViews = timedViews.sorted { (left, right) -> Bool in
return left.timeOffset < right.timeOffset
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/Classes/Full View/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ open class ViewController: UIViewController {

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
animationType = StandardAnimation(duration: duration)
sortFunction = LinearSortFunction(direction: .topToBottom, interObjectDelay: 0.05)
sortFunction = LinearSortFunction(direction: .topToBottom)
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}

Expand All @@ -67,6 +67,6 @@ open class ViewController: UIViewController {
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

animationView?.spruce.animate(animations, duration: duration, animationType: animationType, sortFunction: sortFunction, prepare: false)
animationView?.spruce.animate(animations, duration: .interItemTime(0.1), animationType: animationType, sortFunction: sortFunction, prepare: false)
}
}
Loading