Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
brandon-mcquilkin-kr committed Sep 29, 2017
2 parents 70ba93e + f6cce01 commit 05a45eb
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 79 deletions.
4 changes: 4 additions & 0 deletions M13Checkbox.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
1746F21A1F30C9D7005060B9 /* DefaultValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1746F2191F30C9D7005060B9 /* DefaultValues.swift */; };
43242B551DA7BC1100C6AF91 /* M13CheckboxAddRemovePathGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43242B541DA7BC1100C6AF91 /* M13CheckboxAddRemovePathGenerator.swift */; };
43242B561DA7C2CC00C6AF91 /* M13CheckboxFillController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3591421CAC1F12000FBA3B /* M13CheckboxFillController.swift */; };
43242B571DA7C3CA00C6AF91 /* M13CheckboxBounceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA26E1E41CAC66F000ACB4F4 /* M13CheckboxBounceController.swift */; };
Expand Down Expand Up @@ -71,6 +72,7 @@

/* Begin PBXFileReference section */
142C71FD96ACA2685D246CF8 /* Pods_M13Checkbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_M13Checkbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1746F2191F30C9D7005060B9 /* DefaultValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultValues.swift; sourceTree = "<group>"; };
43242B541DA7BC1100C6AF91 /* M13CheckboxAddRemovePathGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M13CheckboxAddRemovePathGenerator.swift; path = Sources/Paths/M13CheckboxAddRemovePathGenerator.swift; sourceTree = SOURCE_ROOT; };
434D1FF51DABB52300F5A8C8 /* M13CheckboxDisclosurePathGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = M13CheckboxDisclosurePathGenerator.swift; path = Sources/Paths/M13CheckboxDisclosurePathGenerator.swift; sourceTree = SOURCE_ROOT; };
43A4CE6E1E64F86D23A4560F /* Pods-M13Checkbox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-M13Checkbox.release.xcconfig"; path = "Pods/Target Support Files/Pods-M13Checkbox/Pods-M13Checkbox.release.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -228,6 +230,7 @@
EA26E1EC1CAEDD0800ACB4F4 /* Path Generators */,
EAA0983C1CA8BE7F001AAF6E /* Controllers */,
EA6720301C7DFC3D008054BA /* M13Checkbox+IB.swift */,
1746F2191F30C9D7005060B9 /* DefaultValues.swift */,
);
name = Source;
path = M13Checkbox;
Expand Down Expand Up @@ -469,6 +472,7 @@
43242B5C1DA7C8A500C6AF91 /* M13CheckboxDotController.swift in Sources */,
EA96F90A1CBEB5190066C6B7 /* M13CheckboxAnimationGenerator.swift in Sources */,
EA96F9161CBEB5190066C6B7 /* M13Checkbox+IB.swift in Sources */,
1746F21A1F30C9D7005060B9 /* DefaultValues.swift in Sources */,
EA96F9071CBEB5190066C6B7 /* M13Checkbox.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
25 changes: 25 additions & 0 deletions M13Checkbox/DefaultValues.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// ConstantValues.swift
// M13Checkbox
//
// Created by Andrea Antonioni on 30/07/17.
// Copyright © 2017 Brandon McQuilkin. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import Foundation

// A set of default values used to initialize the object
struct DefaultValues {

static let animation: M13Checkbox.Animation = .stroke
static let markType: M13Checkbox.MarkType = .checkmark
static let boxType: M13Checkbox.BoxType = .circle
static let checkState: M13Checkbox.CheckState = .unchecked
static let controller: M13CheckboxController = M13CheckboxStrokeController()

}
14 changes: 7 additions & 7 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,16 @@ view.addSubview(checkbox)
**M13Checkbox**
The main interface for M13Checkbox is the `M13Checkbox` class. It is a subclass of `UIControl` and handles the configurable properties, as well as touch events.

**M13CheckboxManager**
Each `M13Checkbox` references an instance of `M13CheckboxManager`, which controls the appearance and animations of its layers. The manager passes a set of layers to the `M13Checkbox`, which adds the layers to its layer hierarchy. The checkbox then asks the manager to perform the necessary animations on the layers to animate between states. Each animation type has its own subclass of `M13CheckboxManager`. To add an animation, subclass `M13CheckboxManager`, and add the animation type to the `Animation` enum, supporting the animation `Style` if applicable. Take a look at the existing managers to see what variables and functions to override.
**M13CheckboxController**
Each `M13Checkbox` references an instance of `M13CheckboxController`, which controls the appearance and animations of its layers. The controller passes a set of layers to the `M13Checkbox`, which adds the layers to its layer hierarchy. The checkbox then asks the controller to perform the necessary animations on the layers to animate between states. Each animation type has its own subclass of `M13CheckboxController`. To add an animation, subclass `M13CheckboxController`, and add the animation type to the `Animation` enum, supporting `AnimationStyle` if applicable. Take a look at the existing controllers to see what variables and functions to override.

**M13CheckboxAnimationPresets**
Each `M13CheckboxManager` references an instance of `M13CheckboxAnimationPresets`, which generates the animations that will be applied to layers during state transitions. The base class contains animations that are shared between multiple animation styles. An animation can subclass `M13CheckboxAnimationPresets` to generate new animations specific to the animation type.
**M13CheckboxAnimationGenerator**
Each `M13CheckboxController` references an instance of `M13CheckboxAnimationGenerator`, which generates the animations that will be applied to layers during state transitions. The base class contains animations that are shared between multiple animation styles. An animation can subclass `M13CheckboxAnimationGenerator` to generate new animations specific to the animation type.

**M13CheckboxPathPresets**
Each `M13CheckboxManager` references an instance of `M13CheckboxPathPresets`, which generates the paths that will be displayed by the layers. The base class contains paths that are shared between multiple animation styles, as well as some boilerplate code to determine which path to use. Some animations have a subclass of `M13CheckboxPathPresets` to add new paths specific to the animation type, or override existing paths to customize the look.
**M13CheckboxPathGenerator**
Each `M13CheckboxManager` references an instance of `M13CheckboxPathGenerator`, which generates the paths that will be displayed by the layers. The base class contains paths that are shared between multiple animation styles, as well as some boilerplate code to determine which path to use. Some animations have a subclass of `M13CheckboxPathGenerator` to add new paths specific to the animation type, or override existing paths to customize the look.

`M13CheckboxPathPresets` calculates the positions of the points of the checkmark with more than just a basic scaled offset. This allows the checkmark to always look the same, not matter what size the checkbox is. The math contained in the `checkmarkLongArmBoxIntersectionPoint` and `checkmarkLongArmEndPoint` are a simplified version of a human readable solution. To see the math that went into creating these equations, check out the "Math.nb" or the "Math.pdf" in the "Other" folder.
`M13CheckboxPathGenerator` calculates the positions of the points of the checkmark with more than just a basic scaled offset. This allows the checkmark to always look the same, not matter what size the checkbox is. The math contained in the `checkmarkLongArmBoxIntersectionPoint` and `checkmarkLongArmEndPoint` are a simplified version of a human readable solution. To see the math that went into creating these equations, check out the "Math.nb" or the "Math.pdf" in the "Other" folder.

**M13Checkbox+IB**
A shim that gives the ability to set the enum values of `M13Checkbox` in Interface Builder.
Expand Down
25 changes: 25 additions & 0 deletions Sources/DefaultValues.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// ConstantValues.swift
// M13Checkbox
//
// Created by Andrea Antonioni on 30/07/17.
// Copyright © 2017 Brandon McQuilkin. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import Foundation

// A set of default values used to initialize the object
struct DefaultValues {

static let animation: M13Checkbox.Animation = .stroke
static let markType: M13Checkbox.MarkType = .checkmark
static let boxType: M13Checkbox.BoxType = .circle
static let checkState: M13Checkbox.CheckState = .unchecked
static let controller: M13CheckboxController = M13CheckboxStrokeController()

}
8 changes: 4 additions & 4 deletions Sources/M13Checkbox+IB.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public extension M13Checkbox {
if let type = Animation(rawValue: newValue) {
stateChangeAnimation = type
} else {
stateChangeAnimation = .stroke
stateChangeAnimation = DefaultValues.animation
}
}
}
Expand All @@ -38,7 +38,7 @@ public extension M13Checkbox {
if let type = MarkType(rawValue: newValue) {
markType = type
} else {
markType = .checkmark
markType = DefaultValues.markType
}
}
}
Expand All @@ -52,7 +52,7 @@ public extension M13Checkbox {
if let type = BoxType(rawValue: newValue) {
boxType = type
} else {
boxType = .circle
boxType = DefaultValues.boxType
}
}
}
Expand All @@ -66,7 +66,7 @@ public extension M13Checkbox {
if let temp = CheckState(rawValue: newValue) {
checkState = temp
} else {
checkState = .unchecked
checkState = DefaultValues.checkState
}
}
}
Expand Down
19 changes: 3 additions & 16 deletions Sources/M13Checkbox.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,43 +94,30 @@ open class M13Checkbox: UIControl {
switch rawValue {
case "Stroke":
self = .stroke
break
case "Fill":
self = .fill
break
case "BounceStroke":
self = .bounce(.stroke)
break
case "BounceFill":
self = .bounce(.fill)
break
case "ExpandStroke":
self = .expand(.stroke)
break
case "ExpandFill":
self = .expand(.fill)
break
case "FlatStroke":
self = .flat(.stroke)
break
case "FlatFill":
self = .flat(.fill)
break
case "Spiral":
self = .spiral
break
case "FadeStroke":
self = .fade(.stroke)
break
case "FadeFill":
self = .fade(.fill)
break
case "DotStroke":
self = .dot(.stroke)
break
case "DotFill":
self = .dot(.fill)
break
default:
return nil
}
Expand Down Expand Up @@ -228,7 +215,7 @@ open class M13Checkbox: UIControl {

/// The manager that manages display and animations of the checkbox.
/// The default animation is a stroke.
fileprivate var controller: M13CheckboxController = M13CheckboxStrokeController()
fileprivate var controller: M13CheckboxController = DefaultValues.controller

//----------------------------
// MARK: - Initalization
Expand All @@ -251,7 +238,7 @@ open class M13Checkbox: UIControl {
layer.addSublayer(aLayer)
}
controller.tintColor = tintColor
controller.resetLayersForState(.unchecked)
controller.resetLayersForState(DefaultValues.checkState)

let longPressGesture = M13CheckboxGestureRecognizer(target: self, action: #selector(M13Checkbox.handleLongPress(_:)))
addGestureRecognizer(longPressGesture)
Expand Down Expand Up @@ -358,7 +345,7 @@ open class M13Checkbox: UIControl {
}

/// The type of animation to preform when changing from the unchecked state to any other state.
open var stateChangeAnimation: Animation = .stroke {
open var stateChangeAnimation: Animation = DefaultValues.animation {
didSet {

// Remove the sublayers
Expand Down
104 changes: 53 additions & 51 deletions Sources/M13CheckboxController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ internal class M13CheckboxController {
var animationGenerator: M13CheckboxAnimationGenerator = M13CheckboxAnimationGenerator()

/// The current state of the checkbox.
var state: M13Checkbox.CheckState = .unchecked
var state: M13Checkbox.CheckState = DefaultValues.checkState

/// The current tint color.
/// - Note: Subclasses should override didSet to update the layers when this value changes.
Expand All @@ -48,60 +48,62 @@ internal class M13CheckboxController {
var enableMorphing: Bool = true

// The type of mark to display.
var markType: M13Checkbox.MarkType = .checkmark {
willSet {
if markType == newValue {
return
}
setMarkType(type: markType, animated: false)
var markType: M13Checkbox.MarkType {
get {
return _markType
}
set {
setMarkType(type: newValue, animated: false)
}
}

private var _markType: M13Checkbox.MarkType = DefaultValues.markType

func setMarkType(type: M13Checkbox.MarkType, animated: Bool) {
var newPathGenerator: M13CheckboxPathGenerator? = nil
if type != markType {
switch type {
case .checkmark:
newPathGenerator = M13CheckboxCheckPathGenerator()
break
case .radio:
newPathGenerator = M13CheckboxRadioPathGenerator()
break
case .addRemove:
newPathGenerator = M13CheckboxAddRemovePathGenerator()
break
case .disclosure:
newPathGenerator = M13CheckboxDisclosurePathGenerator()
break
}
newPathGenerator?.boxLineWidth = pathGenerator.boxLineWidth
newPathGenerator?.boxType = pathGenerator.boxType
newPathGenerator?.checkmarkLineWidth = pathGenerator.checkmarkLineWidth
newPathGenerator?.cornerRadius = pathGenerator.cornerRadius
newPathGenerator?.size = pathGenerator.size
// Animate the change.
if pathGenerator.pathForMark(state) != nil && animated {
let previousState = state
animate(state, toState: nil, completion: { [weak self] in
self?.pathGenerator = newPathGenerator!
self?.resetLayersForState(previousState)
if self?.pathGenerator.pathForMark(previousState) != nil {
self?.animate(nil, toState: previousState)
}
})
} else if newPathGenerator?.pathForMark(state) != nil && animated {
let previousState = state
pathGenerator = newPathGenerator!
resetLayersForState(nil)
animate(nil, toState: previousState)
} else {
pathGenerator = newPathGenerator!
resetLayersForState(state)
}

markType = type
guard type != _markType else {
return
}
_setMarkType(type: type, animated: animated)
_markType = type
}

private func _setMarkType(type: M13Checkbox.MarkType, animated: Bool) {
var newPathGenerator: M13CheckboxPathGenerator
switch type {
case .checkmark:
newPathGenerator = M13CheckboxCheckPathGenerator()
case .radio:
newPathGenerator = M13CheckboxRadioPathGenerator()
case .addRemove:
newPathGenerator = M13CheckboxAddRemovePathGenerator()
case .disclosure:
newPathGenerator = M13CheckboxDisclosurePathGenerator()
}

newPathGenerator.boxLineWidth = pathGenerator.boxLineWidth
newPathGenerator.boxType = pathGenerator.boxType
newPathGenerator.checkmarkLineWidth = pathGenerator.checkmarkLineWidth
newPathGenerator.cornerRadius = pathGenerator.cornerRadius
newPathGenerator.size = pathGenerator.size

// Animate the change.
if pathGenerator.pathForMark(state) != nil && animated {
let previousState = state
animate(state, toState: nil, completion: { [weak self] in
self?.pathGenerator = newPathGenerator
self?.resetLayersForState(previousState)
if self?.pathGenerator.pathForMark(previousState) != nil {
self?.animate(nil, toState: previousState)
}
})
} else if newPathGenerator.pathForMark(state) != nil && animated {
let previousState = state
pathGenerator = newPathGenerator
resetLayersForState(nil)
animate(nil, toState: previousState)
} else {
pathGenerator = newPathGenerator
resetLayersForState(state)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Paths/M13CheckboxPathGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ internal class M13CheckboxPathGenerator {
var cornerRadius: CGFloat = 3.0

/// The box type to create.
var boxType: M13Checkbox.BoxType = .circle
var boxType: M13Checkbox.BoxType = DefaultValues.boxType

//----------------------------
// MARK: - Box Paths
Expand Down

0 comments on commit 05a45eb

Please sign in to comment.