├── .assets ├── BEMCheckBox box type.jpg ├── BEMCheckBox logo.jpg ├── BEMCheckBox properties.jpg ├── BEMCheckBox-Bounce.gif ├── BEMCheckBox-Fade.gif ├── BEMCheckBox-Fill.gif ├── BEMCheckBox-Flat.gif ├── BEMCheckBox-One-Stroke.gif ├── BEMCheckBox-Stroke.gif └── BEMCheckBox.gif ├── .gitignore ├── .travis.yml ├── BEMCheckBox.podspec.json ├── CHANGELOG.md ├── Classes ├── BEMAnimationManager.swift ├── BEMCheckBox.swift ├── BEMCheckBoxGroup.swift └── BEMPathManager.swift ├── LICENSE ├── Package.swift ├── README.md └── Sample Project ├── BEMCheckBox ├── CheckBox.h └── Info.plist ├── CheckBox.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── CheckBox.xccheckout │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── Bobo.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ ├── BEMCheckBox.xcscheme │ │ ├── CheckBox.xcscheme │ │ └── CheckBoxTests.xcscheme └── xcuserdata │ └── Bobo.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── CheckBox ├── AppDelegate.h ├── AppDelegate.m ├── BEMAnimationsTableViewController.h ├── BEMAnimationsTableViewController.m ├── BEMCurrentSetupTableViewController.h ├── BEMCurrentSetupTableViewController.m ├── BEMMainViewController.h ├── BEMMainViewController.m ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Images.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── app-icon-iphone@2x.png │ │ ├── app-icon-iphone@3x.png │ │ ├── app-icon-setting@2x.png │ │ ├── app-icon-setting@3x.png │ │ ├── app-icon-spotlight@2x.png │ │ └── app-icon-spotlight@3x.png ├── Info.plist └── main.m ├── CheckBoxTests ├── AnimationManangerTests.m ├── CheckBoxTests.m ├── GroupTests.m └── Info.plist └── CheckBoxUITests ├── CheckBoxUITests.m └── Info.plist /.assets/BEMCheckBox box type.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox box type.jpg -------------------------------------------------------------------------------- /.assets/BEMCheckBox logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox logo.jpg -------------------------------------------------------------------------------- /.assets/BEMCheckBox properties.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox properties.jpg -------------------------------------------------------------------------------- /.assets/BEMCheckBox-Bounce.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox-Bounce.gif -------------------------------------------------------------------------------- /.assets/BEMCheckBox-Fade.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox-Fade.gif -------------------------------------------------------------------------------- /.assets/BEMCheckBox-Fill.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox-Fill.gif -------------------------------------------------------------------------------- /.assets/BEMCheckBox-Flat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox-Flat.gif -------------------------------------------------------------------------------- /.assets/BEMCheckBox-One-Stroke.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox-One-Stroke.gif -------------------------------------------------------------------------------- /.assets/BEMCheckBox-Stroke.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox-Stroke.gif -------------------------------------------------------------------------------- /.assets/BEMCheckBox.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/.assets/BEMCheckBox.gif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | .DS_Store? 4 | 5 | # Xcode 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData/ 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xccheckout 25 | *.xcscmblueprint 26 | ._* 27 | .Spotlight-V100 28 | .Trashes 29 | Icon? 30 | ehthumbs.db 31 | Thumbs.db 32 | xcuserdata/ 33 | *.xcuserstate 34 | .idea 35 | 36 | ## Obj-C/Swift specific 37 | *.hmap 38 | *.ipa 39 | *.dSYM.zip 40 | *.dSYM 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | 69 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode11.3 3 | xcode_project: Sample Project/CheckBox.xcodeproj 4 | xcode_scheme: CheckBox 5 | xcode_destination: platform=iOS Simulator,OS=11.3,name=iPhone X 6 | -------------------------------------------------------------------------------- /BEMCheckBox.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BEMCheckBox", 3 | "version": "1.0.0", 4 | "summary": "Tastefully grafted Checkbox for iOS.", 5 | "description": "BEMCheckBox lets your create beautiful check boxes for iOS.", 6 | "homepage": "https://github.com/Boris-Em/BEMSimpleLineGraph", 7 | "screenshots": [ 8 | "http://s12.postimg.org/vn2irahjx/BEMCheck_Box.gif" 9 | ], 10 | "license": { 11 | "type": "MIT", 12 | "file": "LICENSE" 13 | }, 14 | "authors": { 15 | "Boris Emorine": "boris.emorine@gmail.com" 16 | }, 17 | "platforms": { 18 | "ios": "7.0" 19 | }, 20 | "requires_arc": true, 21 | "source": { 22 | "git": "https://github.com/Boris-Em/BEMCheckBox.git", 23 | "tag": "v1.0.0" 24 | }, 25 | "source_files": [ 26 | "Classes", 27 | "Classes/**/*.{h,m}" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [v1.1.0](https://github.com/Boris-Em/BEMCheckBox/tree/1.1.0) (2015-10-17) 4 | [Full Changelog](https://github.com/Boris-Em/BEMCheckBox/compare/1.0.0...1.1.0) 5 | 6 | Added new delegate and BEMCheckBoxDelegate protocol used to receive check box events. 7 | 8 | ## [v1.0.0](https://github.com/Boris-Em/BEMCheckBox/tree/1.0.0) (2015-10-10) 9 | First stable release of **BEMCheckBox** 10 | -------------------------------------------------------------------------------- /Classes/BEMAnimationManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BEMAnimationManager.swift 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/19/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public final class BEMAnimationManager: NSObject { 12 | /** The duration of the animation created by the `BEMAnimationManager` object. */ 13 | @objc public var animationDuration: CFTimeInterval = 0.0 14 | 15 | /** Designated initializer. 16 | * @param animationDuration The duration of the animations created with the `BEMAnimationManager` object. 17 | * @return Returns the a fully initialized `BEMAnimationManager` object. 18 | */ 19 | @objc public init(animationDuration: CFTimeInterval) { 20 | super.init() 21 | self.animationDuration = animationDuration 22 | } 23 | 24 | /** Returns a `CABasicAnimation` which the stroke. 25 | * @param reverse The direction of the animation. Set to YES if the animation should go from opacity 0 to 1, or NO for the opposite. 26 | * @return Returns the `CABasicAnimation` object. 27 | */ 28 | @objc public func strokeAnimationReverse(_ reverse: Bool) -> CABasicAnimation { 29 | let animation = CABasicAnimation(keyPath: "strokeEnd") 30 | if reverse { 31 | animation.fromValue = NSNumber(value: 1.0) 32 | animation.toValue = NSNumber(value: 0.0) 33 | } else { 34 | animation.fromValue = NSNumber(value: 0.0) 35 | animation.toValue = NSNumber(value: 1.0) 36 | } 37 | animation.duration = animationDuration 38 | animation.isRemovedOnCompletion = false 39 | animation.fillMode = .forwards 40 | animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) 41 | 42 | return animation 43 | } 44 | 45 | /** Returns a `CABasicAnimation` which animates the opacity. 46 | * @param reverse The direction of the animation. Set to YES if the animation should go from opacity 0 to 1, or false for the opposite. 47 | * @return Returns the `CABasicAnimation` object. 48 | */ 49 | @objc public func opacityAnimationReverse(_ reverse: Bool) -> CABasicAnimation { 50 | let animation = CABasicAnimation(keyPath: "opacity") 51 | if reverse { 52 | animation.fromValue = NSNumber(value: 1.0) 53 | animation.toValue = NSNumber(value: 0.0) 54 | } else { 55 | animation.fromValue = NSNumber(value: 0.0) 56 | animation.toValue = NSNumber(value: 1.0) 57 | } 58 | animation.duration = animationDuration 59 | animation.isRemovedOnCompletion = false 60 | animation.fillMode = .forwards 61 | animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) 62 | 63 | return animation 64 | } 65 | 66 | /** Returns a `CABasicAnimation` which animates between two paths. 67 | * @param fromPath The path to transform (morph) from. 68 | * @param toPath The path to transform (morph) to. 69 | * @return Returns the `CABasicAnimation` object. 70 | */ 71 | @objc public func morphAnimation(from fromPath: UIBezierPath?, to toPath: UIBezierPath?) -> CABasicAnimation { 72 | let animation = CABasicAnimation(keyPath: "path") 73 | animation.duration = animationDuration 74 | animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) 75 | 76 | animation.fromValue = fromPath?.cgPath 77 | animation.toValue = toPath?.cgPath 78 | 79 | return animation 80 | } 81 | 82 | /** Animation engine to create a fill animation. 83 | * @param bounces The number of bounces for the animation. 84 | * @param amplitude How far does the animation bounce. 85 | * @param reverse Flag to track if the animation should fill or empty the layer. 86 | * @return Returns the `CAKeyframeAnimation` object. 87 | */ 88 | @objc public func fillAnimation(withBounces bounces: Int, amplitude: CGFloat, reverse: Bool) -> CAKeyframeAnimation { 89 | var values: [AnyHashable] = [] 90 | var keyTimes: [NSNumber] = [] 91 | 92 | if reverse { 93 | values.append(NSValue(caTransform3D: CATransform3DMakeScale(1, 1, 1))) 94 | } else { 95 | values.append(NSValue(caTransform3D: CATransform3DMakeScale(0, 0, 0))) 96 | } 97 | 98 | keyTimes.append(0.0) 99 | 100 | for i in 1...bounces { 101 | let scale = (i % 2) != 0 ? (1 + amplitude / CGFloat(i)) : (1 - amplitude / CGFloat(i)) 102 | let time: Double = Double(i) * 1.0 / Double((bounces + 1)) 103 | 104 | values.append(NSValue(caTransform3D: CATransform3DMakeScale(scale, scale, scale))) 105 | keyTimes.append(NSNumber(value: time)) 106 | } 107 | 108 | if reverse { 109 | values.append(NSValue(caTransform3D: CATransform3DMakeScale(0.0001, 0.0001, 0.0001))) 110 | } else { 111 | values.append(NSValue(caTransform3D: CATransform3DMakeScale(1, 1, 1))) 112 | } 113 | 114 | keyTimes.append(NSNumber(value: 1.0)) 115 | 116 | let animation = CAKeyframeAnimation(keyPath: "transform") 117 | animation.values = values 118 | animation.keyTimes = keyTimes 119 | animation.isRemovedOnCompletion = false 120 | animation.fillMode = .forwards 121 | animation.duration = animationDuration 122 | animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) 123 | 124 | return animation 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Classes/BEMCheckBox.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BEMCheckBox.swift 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/19/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** The BEMCheckBoxDelegate protocol. Used to receive life cycle events. */ 12 | @objc public protocol BEMCheckBoxDelegate: NSObjectProtocol { 13 | /** Sent to the delegate every time the check box gets tapped. 14 | * @discussion This method gets triggered after the properties are updated (on), but before the animations, if any, are completed. 15 | * @seealso animationDidStopForCheckBox: 16 | * @param checkBox The BEMCheckBox instance that has been tapped. 17 | */ 18 | @objc optional func didTap(_ checkBox: BEMCheckBox) 19 | 20 | /** Sent to the delegate every time the check box finishes being animated. 21 | * @discussion This method gets triggered after the properties are updated (on), and after the animations are completed. It won't be triggered if no animations are started. 22 | * @seealso didTapCheckBox: 23 | * @param checkBox The BEMCheckBox instance that was animated. 24 | */ 25 | @objc optional func animationDidStop(for checkBox: BEMCheckBox) 26 | } 27 | 28 | /** Tasteful Checkbox for iOS. */ 29 | @IBDesignable 30 | @objc 31 | public class BEMCheckBox: UIControl, CAAnimationDelegate { 32 | 33 | @objc(BEMBoxType) 34 | public enum BoxType : Int { 35 | /** Circled box. */ 36 | case circle 37 | 38 | /** Squared box. */ 39 | case square 40 | } 41 | 42 | @objc(BEMAnimationType) 43 | public enum AnimationType : Int { 44 | /** Animates the box and the check as if they were drawn. 45 | * Should be used with a clear colored `onFillColor` property. */ 46 | case stroke 47 | 48 | /** When tapped, the checkbox is filled from its center. 49 | * Should be used with a colored `onFillColor` property. */ 50 | case fill 51 | 52 | /** Animates the check mark with a bouncy effect. */ 53 | case bounce 54 | 55 | /** Morphs the checkmark from a line. 56 | * Should be used with a colored `onFillColor` property. */ 57 | case flat 58 | 59 | /** Animates the box and check as if they were drawn in one continuous line. 60 | * Should be used with a clear colored `onFillColor` property. */ 61 | case oneStroke 62 | 63 | /** When tapped, the checkbox is fading in or out (opacity). */ 64 | case fade 65 | } 66 | 67 | /** The object that acts as the delegate of the receiving check box. 68 | * @discussion The delegate must adopt the \p BEMCheckBoxDelegate protocol. The delegate is not retained. 69 | */ 70 | @objc @IBOutlet weak public var delegate: BEMCheckBoxDelegate? 71 | 72 | /** This property allows you to retrieve and set (without animation) a value determining whether the BEMCheckBox object is On or Off. 73 | * Default to NO. 74 | */ 75 | @objc @IBInspectable public var on: Bool { 76 | get { return _on } 77 | set { self.setOn(newValue) } 78 | } 79 | 80 | /** The type of box. 81 | * @see BoxType. 82 | */ 83 | @objc public var boxType: BoxType = .circle { 84 | didSet { 85 | pathManager.boxType = boxType 86 | setNeedsLayout() 87 | } 88 | } 89 | 90 | /** The width of the lines of the check mark and the box. Default to 2. */ 91 | @objc @IBInspectable public var lineWidth: CGFloat = 2.0 { 92 | didSet { 93 | pathManager.lineWidth = lineWidth 94 | setNeedsLayout() 95 | } 96 | } 97 | 98 | /** The corner radius which is applied to the box when the boxType is square. Default to 3.0. */ 99 | @objc @IBInspectable public var cornerRadius: CGFloat = 3.0 { 100 | didSet { 101 | pathManager.cornerRadius = cornerRadius 102 | setNeedsLayout() 103 | } 104 | } 105 | 106 | /** The duration in seconds of the animation when the check box switches from on and off. Default to 0. */ 107 | @objc @IBInspectable public var animationDuration: CFTimeInterval = 0.5 { 108 | didSet { 109 | animationManager.animationDuration = animationDuration 110 | } 111 | } 112 | 113 | /** BOOL to control if the box should be hidden or not. Defaults to NO. */ 114 | @objc @IBInspectable public var hideBox = false 115 | 116 | /** The color of the line around the box when it is On. */ 117 | @objc @IBInspectable public var onTintColor: UIColor? = UIColor(red: 0, green: 122.0 / 255.0, blue: 255 / 255, alpha: 1) 118 | 119 | /** The color of the inside of the box when it is On. */ 120 | @objc @IBInspectable public var onFillColor: UIColor? = UIColor.clear { 121 | didSet { 122 | setNeedsLayout() 123 | } 124 | } 125 | 126 | /** The color of the inside of the box when it is Off. */ 127 | @objc @IBInspectable public var offFillColor: UIColor? = UIColor.clear { 128 | didSet { 129 | setNeedsLayout() 130 | } 131 | } 132 | 133 | /** The color of the check mark when it is On. */ 134 | @objc @IBInspectable public var onCheckColor: UIColor? = UIColor(red: 0, green: 122.0 / 255.0, blue: 255 / 255, alpha: 1) { 135 | didSet { 136 | setNeedsLayout() 137 | } 138 | } 139 | 140 | /** The layer where the box is drawn when the check box is set to On. */ 141 | private var onBoxLayer: CAShapeLayer? 142 | 143 | /** The layer where the box is drawn when the check box is set to Off. */ 144 | private var offBoxLayer: CAShapeLayer? 145 | 146 | /** The layer where the check mark is drawn when the check box is set to On. */ 147 | private var checkMarkLayer: CAShapeLayer? 148 | 149 | /** The BEMAnimationManager object used to generate animations. */ 150 | private lazy var animationManager: BEMAnimationManager = { 151 | let animationManager = BEMAnimationManager(animationDuration: animationDuration) 152 | return animationManager 153 | }() 154 | 155 | 156 | /** The BEMPathManager object used to generate paths. */ 157 | private lazy var pathManager: BEMPathManager = { 158 | let pathManager = BEMPathManager() 159 | pathManager.lineWidth = lineWidth 160 | pathManager.cornerRadius = cornerRadius 161 | pathManager.boxType = boxType 162 | pathManager.size = frame.height 163 | return pathManager 164 | }() 165 | 166 | /** The group this box is associated with. */ 167 | @objc public var group: BEMCheckBoxGroup? 168 | 169 | /** The animation type when the check mark gets set to On. 170 | * @warning Some animations might not look as intended if the different colors of the control are not appropriatly configured. 171 | * @see BEMAnimationType. 172 | */ 173 | @objc public var onAnimationType: AnimationType = .stroke 174 | 175 | /** The animation type when the check mark gets set to Off. 176 | * @warning Some animations might not look as intended if the different colors of the control are not appropriatly configured. 177 | * @see BEMAnimationType. 178 | */ 179 | @objc public var offAnimationType: AnimationType = .stroke 180 | 181 | /** If the checkbox width or height is smaller than this value, the touch area will be increased. Allows for visually small checkboxes to still be easily tapped. Default: (44, */ 182 | @objc @IBInspectable var minimumTouchSize = CGSize(width: 44, height: 44) 183 | 184 | // MARK: Initialization 185 | 186 | @objc public override init(frame: CGRect) { 187 | super.init(frame: frame) 188 | commonInit() 189 | } 190 | 191 | @objc public required init?(coder: NSCoder) { 192 | super.init(coder: coder) 193 | commonInit() 194 | } 195 | 196 | private func commonInit() { 197 | // Default values 198 | tintColor = UIColor.lightGray 199 | backgroundColor = UIColor.clear 200 | 201 | addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTapCheckBox(_:)))) 202 | } 203 | 204 | public override var frame: CGRect { 205 | didSet { 206 | pathManager.size = frame.height 207 | } 208 | } 209 | 210 | override public func layoutSubviews() { 211 | self.setupLayers() 212 | } 213 | 214 | override public var intrinsicContentSize: CGSize { 215 | return frame.size 216 | } 217 | 218 | // MARK: Setters 219 | 220 | private var _on: Bool = false 221 | 222 | internal func setOn(_ on: Bool, animated: Bool, notifyGroup: Bool) { 223 | self._on = on 224 | 225 | if animated { 226 | setupLayers() 227 | } else { 228 | setNeedsLayout() 229 | } 230 | 231 | if on { 232 | if animated { 233 | addOnAnimation() 234 | } 235 | } else { 236 | if animated { 237 | addOffAnimation() 238 | } else { 239 | onBoxLayer?.removeFromSuperlayer() 240 | onBoxLayer = nil 241 | 242 | checkMarkLayer?.removeFromSuperlayer() 243 | checkMarkLayer = nil 244 | } 245 | } 246 | 247 | if notifyGroup { 248 | group?.notifyCheckBoxSelectionChanged(self) 249 | } 250 | } 251 | 252 | /** Set the state of the check box to On or Off, optionally animating the */ 253 | @objc public func setOn(_ on: Bool, animated: Bool = false) { 254 | setOn(on, animated: animated, notifyGroup: false) 255 | } 256 | 257 | // MARK: Gesture Recognizer 258 | @objc func handleTapCheckBox(_ recognizer: UITapGestureRecognizer?) { 259 | // If we have a group that requires a selection, and we're already selected, don't allow a deselection 260 | if group != nil && group?.mustHaveSelection == true && on { 261 | return 262 | } 263 | 264 | setOn(!on, animated: true) 265 | if delegate?.responds(to: #selector(BEMCheckBoxDelegate.didTap(_:))) == true { 266 | delegate?.didTap?(self) 267 | } 268 | sendActions(for: .valueChanged) 269 | } 270 | 271 | // MARK: - Helper methods - 272 | 273 | // MARK: Increase touch area 274 | 275 | override public func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 276 | var found = super.point(inside: point, with: event) 277 | 278 | let minimumSize = minimumTouchSize 279 | let width = bounds.width 280 | let height = bounds.height 281 | 282 | if found == false && (width < minimumSize.width || height < minimumSize.height) { 283 | let increaseWidth = minimumSize.width - width 284 | let increaseHeight = minimumSize.height - height 285 | 286 | let rect = bounds.insetBy(dx: -increaseWidth / 2, dy: -increaseHeight / 2) 287 | 288 | found = rect.contains(point) 289 | } 290 | 291 | return found 292 | } 293 | 294 | // MARK: Drawings 295 | 296 | /** Draws the entire checkbox, depending on the current state of the on property. */ 297 | private func setupLayers() { 298 | if !hideBox { 299 | setupBoxOffLayer() 300 | } else { 301 | offBoxLayer?.removeFromSuperlayer() 302 | offBoxLayer = nil 303 | } 304 | 305 | if !hideBox && on { 306 | setupBoxOnLayer() 307 | } 308 | 309 | if on { 310 | setupCheckmarkLayer() 311 | } 312 | } 313 | 314 | /** Draws the box used when the checkbox is set to Off. */ 315 | private func setupBoxOffLayer() { 316 | if offBoxLayer == nil { 317 | offBoxLayer = CAShapeLayer() 318 | offBoxLayer?.rasterizationScale = 2.0 * UIScreen.main.scale 319 | offBoxLayer?.shouldRasterize = true 320 | } 321 | 322 | offBoxLayer?.frame = bounds 323 | offBoxLayer?.path = pathManager.pathForBox().cgPath 324 | offBoxLayer?.fillColor = offFillColor?.cgColor 325 | offBoxLayer?.strokeColor = tintColor?.cgColor 326 | offBoxLayer?.lineWidth = lineWidth 327 | 328 | self.layer.insertSublayer(offBoxLayer!, at: 0) 329 | } 330 | 331 | /** Draws the box when the checkbox is set to On. 332 | */ 333 | private func setupBoxOnLayer() { 334 | if onBoxLayer == nil { 335 | onBoxLayer = CAShapeLayer() 336 | onBoxLayer?.rasterizationScale = 2.0 * UIScreen.main.scale 337 | onBoxLayer?.shouldRasterize = true 338 | } 339 | 340 | onBoxLayer?.frame = bounds 341 | onBoxLayer?.path = pathManager.pathForBox().cgPath 342 | onBoxLayer?.lineWidth = lineWidth 343 | onBoxLayer?.fillColor = onFillColor?.cgColor 344 | onBoxLayer?.strokeColor = onTintColor?.cgColor 345 | 346 | layer.addSublayer(onBoxLayer!) 347 | } 348 | 349 | /** Draws the check mark when the checkbox is set to On. 350 | */ 351 | private func setupCheckmarkLayer() { 352 | if checkMarkLayer == nil { 353 | checkMarkLayer = CAShapeLayer() 354 | checkMarkLayer?.rasterizationScale = 2.0 * UIScreen.main.scale 355 | checkMarkLayer?.shouldRasterize = true 356 | checkMarkLayer?.lineCap = .round 357 | checkMarkLayer?.lineJoin = .round 358 | } 359 | 360 | checkMarkLayer?.frame = bounds 361 | checkMarkLayer?.path = pathManager.pathForCheckMark().cgPath 362 | checkMarkLayer?.strokeColor = onCheckColor?.cgColor 363 | checkMarkLayer?.lineWidth = lineWidth 364 | checkMarkLayer?.fillColor = UIColor.clear.cgColor 365 | 366 | layer.addSublayer(checkMarkLayer!) 367 | } 368 | 369 | // MARK: Animations 370 | 371 | private func addOnAnimation() { 372 | if animationDuration == 0.0 { 373 | return 374 | } 375 | 376 | switch onAnimationType { 377 | case .stroke: 378 | let animation = animationManager.strokeAnimationReverse(false) 379 | onBoxLayer?.add(animation, forKey: "strokeEnd") 380 | animation.delegate = self 381 | checkMarkLayer?.add(animation, forKey: "strokeEnd") 382 | 383 | return 384 | 385 | case .fill: 386 | let wiggle = animationManager.fillAnimation(withBounces: 1, amplitude: 0.18, reverse: false) 387 | onBoxLayer?.add(wiggle, forKey: "transform") 388 | 389 | let opacityAnimation = animationManager.opacityAnimationReverse(false) 390 | opacityAnimation.delegate = self 391 | checkMarkLayer?.add(opacityAnimation, forKey: "opacity") 392 | 393 | return 394 | 395 | case .bounce: 396 | let amplitude: CGFloat = (boxType == .square) ? 0.20 : 0.35 397 | 398 | let wiggle = animationManager.fillAnimation(withBounces: 1, amplitude: amplitude, reverse: false) 399 | wiggle.delegate = self 400 | checkMarkLayer?.add(wiggle, forKey: "transform") 401 | 402 | let opacity = animationManager.opacityAnimationReverse(false) 403 | opacity.duration = animationDuration / 1.4 404 | onBoxLayer?.add(opacity, forKey: "opacity") 405 | 406 | return 407 | 408 | case .flat: 409 | let morphAnimation = animationManager.morphAnimation( 410 | from: pathManager.pathForFlatCheckMark(), 411 | to: pathManager.pathForCheckMark()) 412 | let opacity = animationManager.opacityAnimationReverse(false) 413 | 414 | morphAnimation.delegate = self 415 | opacity.duration = animationDuration / 5 416 | 417 | onBoxLayer?.add(opacity, forKey: "opacity") 418 | checkMarkLayer?.add(morphAnimation, forKey: "path") 419 | checkMarkLayer?.add(opacity, forKey: "opacity") 420 | 421 | return 422 | 423 | case .oneStroke: 424 | // Temporary set the path of the checkmark to the long checkmark 425 | self.checkMarkLayer?.path = pathManager.pathForLongCheckMark().reversing().cgPath 426 | 427 | let boxStrokeAnimation = animationManager.strokeAnimationReverse(false) 428 | let checkStrokeAnimation = animationManager.strokeAnimationReverse(false) 429 | let checkMorphAnimation = animationManager.morphAnimation( 430 | from: pathManager.pathForLongCheckMark(), 431 | to: pathManager.pathForCheckMark()) 432 | boxStrokeAnimation.duration = boxStrokeAnimation.duration / 2 433 | onBoxLayer?.add(boxStrokeAnimation, forKey: "strokeEnd") 434 | 435 | checkStrokeAnimation.duration = checkStrokeAnimation.duration / 3 436 | checkStrokeAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut) 437 | checkStrokeAnimation.fillMode = .backwards 438 | checkStrokeAnimation.beginTime = CACurrentMediaTime() + boxStrokeAnimation.duration 439 | checkMarkLayer?.add(checkStrokeAnimation, forKey: "strokeEnd") 440 | 441 | checkMorphAnimation.duration = checkMorphAnimation.duration / 6 442 | checkMorphAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut) 443 | checkMorphAnimation.beginTime = CACurrentMediaTime() + boxStrokeAnimation.duration + checkStrokeAnimation.duration 444 | checkMorphAnimation.isRemovedOnCompletion = false 445 | checkMorphAnimation.fillMode = .forwards 446 | checkMorphAnimation.delegate = self 447 | checkMarkLayer?.add(checkMorphAnimation, forKey: "path") 448 | 449 | return 450 | 451 | default: 452 | let animation = animationManager.opacityAnimationReverse(false) 453 | onBoxLayer?.add(animation, forKey: "opacity") 454 | animation.delegate = self 455 | checkMarkLayer?.add(animation, forKey: "opacity") 456 | 457 | return 458 | } 459 | } 460 | 461 | private func addOffAnimation() { 462 | if animationDuration == 0.0 { 463 | onBoxLayer?.removeFromSuperlayer() 464 | onBoxLayer = nil 465 | 466 | checkMarkLayer?.removeFromSuperlayer() 467 | checkMarkLayer = nil 468 | return 469 | } 470 | 471 | switch offAnimationType { 472 | case .stroke: 473 | let animation = animationManager.strokeAnimationReverse(true) 474 | onBoxLayer?.add(animation, forKey: "strokeEnd") 475 | animation.delegate = self 476 | checkMarkLayer?.add(animation, forKey: "strokeEnd") 477 | 478 | return 479 | 480 | case .fill: 481 | let wiggle = animationManager.fillAnimation(withBounces: 1, amplitude: 0.18, reverse: true) 482 | wiggle.duration = animationDuration 483 | wiggle.delegate = self 484 | onBoxLayer?.add(wiggle, forKey: "transform") 485 | 486 | let opacity = animationManager.opacityAnimationReverse(true) 487 | checkMarkLayer?.add(opacity, forKey: "opacity") 488 | 489 | return 490 | 491 | case .bounce: 492 | let amplitude: CGFloat = (boxType == .square) ? 0.20 : 0.35 493 | let wiggle = animationManager.fillAnimation(withBounces: 1, amplitude: amplitude, reverse: true) 494 | wiggle.duration = animationDuration / 1.1 495 | checkMarkLayer?.add(wiggle, forKey: "transform") 496 | 497 | let opacity = animationManager.opacityAnimationReverse(true) 498 | opacity.delegate = self 499 | onBoxLayer?.add(opacity, forKey: "opacity") 500 | 501 | return 502 | 503 | case .flat: 504 | let morphAnimation = animationManager.morphAnimation( 505 | from: pathManager.pathForCheckMark(), 506 | to: pathManager.pathForFlatCheckMark()) 507 | let opacity = animationManager.opacityAnimationReverse(true) 508 | 509 | morphAnimation.delegate = self 510 | opacity.duration = animationDuration 511 | 512 | onBoxLayer?.add(opacity, forKey: "opacity") 513 | checkMarkLayer?.add(morphAnimation, forKey: "path") 514 | checkMarkLayer?.add(opacity, forKey: "opacity") 515 | 516 | return 517 | 518 | case .oneStroke: 519 | checkMarkLayer?.path = pathManager.pathForLongCheckMark().reversing().cgPath 520 | 521 | let checkMorphAnimation = animationManager.morphAnimation( 522 | from: pathManager.pathForCheckMark(), 523 | to: pathManager.pathForLongCheckMark()) 524 | let checkStrokeAnimation = animationManager.strokeAnimationReverse(true) 525 | 526 | checkMorphAnimation.delegate = nil 527 | checkMorphAnimation.duration = CFTimeInterval(checkMorphAnimation.duration / 6) 528 | checkMarkLayer?.add(checkMorphAnimation, forKey: "path") 529 | 530 | checkStrokeAnimation.delegate = nil 531 | checkStrokeAnimation.beginTime = CACurrentMediaTime() + checkMorphAnimation.duration 532 | checkStrokeAnimation.duration = CFTimeInterval(checkStrokeAnimation.duration / 3) 533 | checkMarkLayer?.add(checkStrokeAnimation, forKey: "strokeEnd") 534 | 535 | weak var weakSelf = self 536 | DispatchQueue.main.asyncAfter( 537 | deadline: .now() + Double(Int64(CACurrentMediaTime() + 538 | checkMorphAnimation.duration + checkStrokeAnimation.duration * 539 | Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), 540 | execute: { 541 | weakSelf?.checkMarkLayer?.lineCap = .butt 542 | }) 543 | 544 | let boxStrokeAnimation = animationManager.strokeAnimationReverse(true) 545 | boxStrokeAnimation.beginTime = CACurrentMediaTime() + checkMorphAnimation.duration + checkStrokeAnimation.duration 546 | boxStrokeAnimation.duration = CFTimeInterval(boxStrokeAnimation.duration / 2) 547 | boxStrokeAnimation.delegate = self 548 | onBoxLayer?.add(boxStrokeAnimation, forKey: "strokeEnd") 549 | 550 | return 551 | 552 | default: 553 | let animation = animationManager.opacityAnimationReverse(true) 554 | onBoxLayer?.add(animation, forKey: "opacity") 555 | animation.delegate = self 556 | checkMarkLayer?.add(animation, forKey: "opacity") 557 | 558 | return 559 | } 560 | } 561 | 562 | // MARK: Animation Delegate 563 | 564 | public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { 565 | if flag == true && on == false { 566 | onBoxLayer?.removeFromSuperlayer() 567 | onBoxLayer = nil 568 | 569 | checkMarkLayer?.removeFromSuperlayer() 570 | checkMarkLayer = nil 571 | } 572 | 573 | if delegate?.responds(to: #selector(BEMCheckBoxDelegate.animationDidStop(for:))) == true { 574 | delegate?.animationDidStop?(for: self) 575 | } 576 | } 577 | } 578 | 579 | 580 | -------------------------------------------------------------------------------- /Classes/BEMCheckBoxGroup.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BEMCheckBoxGroup.swift 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/19/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @objc 12 | public class BEMCheckBoxGroup: NSObject { 13 | /** An array of check boxes in this group. 14 | */ 15 | @objc public private(set) var checkBoxes = NSHashTable(options: .weakMemory) 16 | 17 | /** The currently selected check box. Only can be nil if mustHaveSelection is NO. Setting this value will cause the other check boxes to deselect automatically. 18 | */ 19 | @objc public var selectedCheckBox: BEMCheckBox? { 20 | get { 21 | var selected: BEMCheckBox? = nil 22 | 23 | for checkBox in checkBoxes.allObjects { 24 | if checkBox.on { 25 | selected = checkBox 26 | break 27 | } 28 | } 29 | 30 | return selected 31 | } 32 | set { 33 | if newValue != nil { 34 | for checkBox in checkBoxes.allObjects { 35 | let shouldBeOn = checkBox == newValue 36 | if checkBox.on != shouldBeOn { 37 | checkBox.setOn(shouldBeOn, animated: true, notifyGroup: false) 38 | } 39 | } 40 | } else { 41 | // Selection is nil 42 | if mustHaveSelection && checkBoxes.count > 0 { 43 | // We must have a selected checkbox, so re-call this method with the first checkbox 44 | self.selectedCheckBox = checkBoxes.allObjects.first 45 | } else { 46 | for checkBox in checkBoxes.allObjects { 47 | let shouldBeOn = false 48 | if checkBox.on != shouldBeOn { 49 | checkBox.setOn(shouldBeOn, animated: true, notifyGroup: false) 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | 57 | /** If YES, don't allow the user to unselect all options, must have single selection at all times. Default to NO. 58 | */ 59 | @objc public var mustHaveSelection = false { 60 | didSet { 61 | // If it must have a selection and we currently don't, select the first box 62 | if mustHaveSelection && selectedCheckBox == nil { 63 | selectedCheckBox = checkBoxes.allObjects.first 64 | } 65 | } 66 | } 67 | 68 | @objc override public init() { 69 | super.init() 70 | } 71 | 72 | /** Creates a new group with the list of check boxes. 73 | */ 74 | @objc convenience public init(checkBoxes: [BEMCheckBox]) { 75 | self.init() 76 | 77 | for checkbox in checkBoxes { 78 | addCheckBoxToGroup(checkbox) 79 | } 80 | } 81 | 82 | /** Tests whether the checkbox is in this group */ 83 | @objc public func contains(_ checkBox: BEMCheckBox) -> Bool { 84 | return checkBoxes.contains(checkBox) 85 | } 86 | 87 | /** Adds a check box to this group. Check boxes can only belong to a single group, adding to a group removes it from its current group. 88 | */ 89 | @objc public func addCheckBoxToGroup(_ checkBox: BEMCheckBox) { 90 | if checkBoxes.contains(checkBox) { return } 91 | 92 | if checkBox.group != nil { 93 | checkBox.group?.removeCheckBoxFromGroup(checkBox) 94 | } 95 | 96 | checkBoxes.add(checkBox) 97 | 98 | checkBox.setOn(false, animated: false, notifyGroup: false) 99 | checkBox.group = self 100 | } 101 | 102 | /** Removes a check box from this group. */ 103 | @objc public func removeCheckBoxFromGroup(_ checkBox: BEMCheckBox) { 104 | if !checkBoxes.contains(checkBox) { 105 | // Not in this group 106 | return 107 | } 108 | 109 | checkBoxes.remove(checkBox) 110 | checkBox.group = nil 111 | } 112 | 113 | // MARK: Private methods called by BEMCheckBox 114 | 115 | internal func notifyCheckBoxSelectionChanged(_ checkBox: BEMCheckBox) { 116 | if checkBox.on { 117 | // Change selected checkbox to this one 118 | selectedCheckBox = checkBox 119 | } else if checkBox == selectedCheckBox { 120 | // Selected checkbox was this one, clear it 121 | selectedCheckBox = nil 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Classes/BEMPathManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BEMPathManager.swift 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/19/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class BEMPathManager: NSObject { 12 | /** The paths are assumed to be created in squares. 13 | * This is the size of width, or height, of the paths that will be created. 14 | */ 15 | var size: CGFloat = 0.0 16 | 17 | /** The width of the lines on the created paths. */ 18 | var lineWidth: CGFloat = 0.0 19 | 20 | /** The corner radius of the path when the boxType is BEMBoxTypeSquare. */ 21 | var cornerRadius: CGFloat = 0.0 22 | 23 | /** The type of box. 24 | * Depending on the box type, paths may be created differently 25 | * @see BEMBoxType 26 | */ 27 | var boxType: BEMCheckBox.BoxType = .circle 28 | 29 | /** Returns a UIBezierPath object for the box of the checkbox 30 | * @returns The path of the box. 31 | */ 32 | func pathForBox() -> UIBezierPath { 33 | var path: UIBezierPath 34 | 35 | switch boxType { 36 | case .square: 37 | let offset = lineWidth / 2.0 38 | let size = self.size - lineWidth 39 | 40 | path = UIBezierPath( 41 | roundedRect: CGRect( 42 | x: 0.0, y: 0.0, 43 | width: size, height: size), 44 | cornerRadius: cornerRadius) 45 | path.apply(CGAffineTransform.identity.rotated(by: CGFloat.pi * 2.5)) 46 | path.apply(CGAffineTransform(translationX: size + offset, y: offset)) 47 | 48 | default: 49 | let radius: CGFloat = (size - lineWidth) / 2 50 | 51 | path = UIBezierPath( 52 | arcCenter: CGPoint(x: size / 2, y: size / 2), 53 | radius: radius, 54 | startAngle: -.pi / 4, 55 | endAngle: 2 * .pi - .pi / 4, 56 | clockwise: true) 57 | } 58 | 59 | return path 60 | } 61 | 62 | /** Returns a UIBezierPath object for the checkmark of the checkbox 63 | * @returns The path of the checkmark. 64 | */ 65 | func pathForCheckMark() -> UIBezierPath { 66 | let checkMarkPath = UIBezierPath() 67 | 68 | checkMarkPath.move(to: CGPoint(x: size / 3.1578, y: size / 2)) 69 | checkMarkPath.addLine(to: CGPoint(x: size / 2.0618, y: size / 1.57894)) 70 | checkMarkPath.addLine(to: CGPoint(x: size / 1.3953, y: size / 2.7272)) 71 | 72 | if boxType == .square { 73 | // If we use a square box, the check mark should be a little bit bigger 74 | checkMarkPath.apply(CGAffineTransform(scaleX: 1.5, y: 1.5)) 75 | checkMarkPath.apply(CGAffineTransform(translationX: -size / 4, y: -size / 4)) 76 | } 77 | 78 | return checkMarkPath 79 | } 80 | 81 | /** Returns a UIBezierPath object for an extra long checkmark which is in contact with the box. 82 | * @returns The path of the checkmark. 83 | */ 84 | func pathForLongCheckMark() -> UIBezierPath { 85 | let checkMarkPath = UIBezierPath() 86 | 87 | checkMarkPath.move(to: CGPoint(x: size / 3.1578, y: size / 2)) 88 | checkMarkPath.addLine(to: CGPoint(x: size / 2.0618, y: size / 1.57894)) 89 | 90 | if boxType == .square { 91 | // If we use a square box, the check mark should be a little bit bigger 92 | checkMarkPath.addLine(to: CGPoint(x: size / 1.2053, y: size / 4.5272)) 93 | checkMarkPath.apply(CGAffineTransform(scaleX: 1.5, y: 1.5)) 94 | checkMarkPath.apply(CGAffineTransform(translationX: -size / 4, y: -size / 4)) 95 | } else { 96 | checkMarkPath.addLine(to: CGPoint(x: size / 1.1553, y: size / 5.9272)) 97 | } 98 | 99 | return checkMarkPath 100 | } 101 | 102 | /** Returns a UIBezierPath object for the flat checkmark of the checkbox 103 | * @see BEMAnimationTypeFlat 104 | * @returns The path of the flat checkmark. 105 | */ 106 | func pathForFlatCheckMark() -> UIBezierPath { 107 | let flatCheckMarkPath = UIBezierPath() 108 | flatCheckMarkPath.move(to: CGPoint(x: size / 4, y: size / 2)) 109 | flatCheckMarkPath.addLine(to: CGPoint(x: size / 2, y: size / 2)) 110 | flatCheckMarkPath.addLine(to: CGPoint(x: size / 1.2, y: size / 2)) 111 | 112 | return flatCheckMarkPath 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Boris Emorine. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "BEMCheckBox", 6 | platforms: [ 7 | .iOS(.v8) 8 | ], 9 | products: [ 10 | .library(name: "BEMCheckBox", targets: ["BEMCheckBox"]) 11 | ], 12 | targets: [ 13 | .target(name: "BEMCheckBox", dependencies: [], path: "Classes") 14 | ] 15 | ) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BEMCheckBox 2 | [![Build Status](https://travis-ci.org/Boris-Em/BEMCheckBox.svg)](https://travis-ci.org/Boris-Em/BEMCheckBox) 3 | [![Version](https://img.shields.io/cocoapods/v/BEMCheckBox.svg?style=flat)](http://cocoadocs.org/docsets/BEMCheckBox) 4 | [![License](https://img.shields.io/cocoapods/l/BEMCheckBox.svg?style=flat)](http://cocoadocs.org/docsets/BEMCheckBox) 5 | [![Platform](https://img.shields.io/cocoapods/p/BEMCheckBox.svg?style=flat)](http://cocoadocs.org/docsets/BEMCheckBox) 6 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 7 | 8 |

9 | 10 | **BEMCheckBox** is an open source library making it easy to create beautiful, highly customizable, animated checkboxes for iOS. 11 | 12 | ## Table of Contents 13 | 14 | * [**Project Details**](#project-details) 15 | * [Requirements](#requirements) 16 | * [License](#license) 17 | * [Support](#support) 18 | * [Sample App](#sample-app) 19 | * [React Native](#react-native) 20 | * [NativeScript](#nativescript) 21 | * [Xamarin](#xamarin) 22 | * [**Getting Started**](#getting-started) 23 | * [Installation](#installation) 24 | * [Setup](#setup) 25 | * [**Documentation**](#documentation) 26 | * [Enabling / Disabling the Checkbox](#enabling--disabling-the-checkbox) 27 | * [Reloading](#reloading) 28 | * [Group / Radio Button Functionality](#group--radio-button-functionality) 29 | * [Delegate](#delegate) 30 | * [Customization](#customization) 31 | 32 | ## Project Details 33 | Learn more about the **BEMCheckBox** project, licensing, support etc. 34 | 35 |

36 | 37 | ### Requirements 38 | - Requires iOS 7 or later. The sample project is optimized for iOS 9. 39 | - Requires Automatic Reference Counting (ARC). 40 | - Optimized for ARM64 Architecture. 41 | 42 | ### License 43 | See the [License](https://github.com/Boris-Em/BEMCheckBox/blob/master/LICENSE). You are free to make changes and use this in either personal or commercial projects. Attribution is not required, but highly appreciated. A little "Thanks!" (or something to that affect) is always welcome. If you use **BEMCheckBox** in your app, please let us know! 44 | 45 | ### Support 46 | [![Gitter chat](https://badges.gitter.im/Boris-Em/BEMCheckBox.png)](https://gitter.im/Boris-Em/BEMCheckBox) 47 | Join us on [Gitter](https://gitter.im/Boris-Em/BEMCheckBox) if you need any help or want to talk about the project. 48 | 49 | ### Sample App 50 | The iOS Sample App included with this project demonstrates one way to correctly setup and use **BEMCheckBox**. It also offers the possibility to customize the checkbox within the app. 51 | 52 | ### React Native 53 | **BEMCheckBox** can be used with React Native: [React-Native-BEMCheckBox](https://github.com/torifat/react-native-bem-check-box) 54 | 55 | ### NativeScript 56 | **BEMCheckBox** can be used with NativeScript: [NativeScript-BEMCheckBox](https://github.com/nstudio/nativescript-checkbox) 57 | 58 | ### Xamarin 59 | **BEMCheckBox** can also be used with Xamarin: [XPlugins.iOS.BEMCheckBox](https://github.com/saturdaymp/XPlugins.iOS.BEMCheckBox) 60 | 61 | ## Getting Started 62 | It only takes a few simple steps to install and setup **BEMCheckBox** to your project. 63 | 64 | ### Installation 65 | 66 | #### Swift Package Manager 67 | Add `https://github.com/Boris-Em/BEMCheckBox` as a dependency to your Package.swift file or select `File -> Swift Packages -> Add Package Dependency...` in Xcode. 68 | 69 | #### CocoaPods 70 | The easiest way to install **BEMCheckBox** is to use CocoaPods. To do so, simply add the following line to your `Podfile`: 71 |
pod 'BEMCheckBox'
72 | 73 | 74 | #### Carthage 75 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 76 | 77 | Run `carthage update` after adding **BEMCheckBox** to your Cartfile to build the framework. Drag the built `BEMCheckBox.framework` into your Xcode project. 78 | 79 | #### Manually 80 | Finally, you can install **BEMCheckBox** manually. Simply drag and drop the *Classes* folder into your Xcode project. When you do so, make sure to check the "*Copy items into destination group's folder*" box. 81 | 82 | ### Setup 83 | Setting up **BEMCheckBox** to your project couldn't be more simple. It is modeled after `UISwitch`. In fact, you could just replace instances of `UISwitch` by **BEMCheckBox** in your project! 84 | Here are the steps to follow to get everything up and running: 85 | 86 | 1. Import `"BEMCheckBox.h"` to the header of your view controller: 87 | 88 | ```objective-c 89 | #import "BEMCheckBox.h" 90 | ``` 91 | 92 | 2. **BEMCheckBox** can either be initialized programatically (through code) or with Interface Builder (Storyboard file). Use the method that makes the most sense for your project. 93 | 94 | **Programmatical Initialization** 95 | Just add the following code to your implementation (usually in the `viewDidLoad` method of your View Controller). 96 | 97 | ```objective-c 98 | BEMCheckBox *myCheckBox = [[BEMCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 50)]; 99 | [self.view addSubview:myCheckBox]; 100 | ``` 101 | 102 | **Interface Builder Initialization** 103 | 1 - Drag a `UIView` to your `UIViewController`. 104 | 2 - Change the class of the new `UIView` to `BEMCheckBox`. 105 | 3 - Select the `BEMCheckBox` and open the Attributes Inspector. Most of the customizable properties can easily be set from the Attributes Inspector. The Sample App demonstrates this capability. 106 | 107 | ## Documentation 108 | All of the methods and properties available for **BEMCheckBox** are documented below. 109 | 110 | ### Enabling / Disabling the Checkbox 111 | ##### The `on` Property 112 | Just like `UISwitch`, **BEMCheckBox** provides the boolean property `on` that allows you to retrieve and set (without animation) a value determining wether the BEMCheckBox object is `on` or `off`. Defaults to `NO`. 113 | Example usage: 114 | ```objective-c 115 | self.myCheckBox.on = YES; 116 | ``` 117 | ##### `setOn:animated:` 118 | Just like `UISwitch`, **BEMCheckBox** provides an instance method `setOn:animated:` that sets the state of the checkbox to On or Off, optionally animating the transition. 119 | Example usage: 120 | ```objective-c 121 | [self.myCheckBox setOn:YES animated:YES]; 122 | ``` 123 | 124 | ### Reloading 125 | The instance method `reload` lets you redraw the entire checkbox, keeping the current `on` value. 126 | Example usage: 127 | ```objective-c 128 | [self.myCheckBox reload] 129 | ``` 130 | 131 | ### Group / Radio Button Functionality 132 | **BEMCheckBox**es can easily be grouped together to form radio button functionality. This will automatically manage the state of each checkbox in the group, so that only one is selected at a time, and can optionally require that the group has a selection at all times. 133 | 134 | ```objective-c 135 | self.group = [BEMCheckBoxGroup groupWithCheckBoxes:@[self.checkBox1, self.checkBox2, self.checkBox3]]; 136 | self.group.selectedCheckBox = self.checkBox2; // Optionally set which checkbox is pre-selected 137 | self.group.mustHaveSelection = YES; // Define if the group must always have a selection 138 | ``` 139 | 140 | To see which checkbox is selected in that group, just ask for it: 141 | ```objective-c 142 | BEMCheckBox *selection = self.group.selectedCheckBox; 143 | ``` 144 | 145 | To manually update the selection for a group, just set it: 146 | ```objective-c 147 | self.group.selectedCheckBox = self.checkBox1; 148 | ``` 149 | 150 | ### Delegate 151 | **BEMCheckBox** uses a delegate to receive check box events. The delegate object must conform to the `BEMCheckBoxDelegate` protocol, which is composed of two optional methods: 152 | 153 | - `didTapCheckBox:` 154 | Sent to the delegate every time the check box gets tapped, after its properties are updated (`on`), but before the animations are completed. 155 | 156 | - `animationDidStopForCheckBox:` 157 | Sent to the delegate every time the check box finishes being animated. 158 | 159 | ### Customization 160 | **BEMCheckBox** is exclusively customizable though properties. 161 | The following diagram provides a good overview: 162 |

163 | 164 | 165 | ##### Apparence Properties 166 | `lineWidth` - CGFloat 167 | The width of the lines of the check mark and box. Defaults to 2.0. 168 | 169 | `hideBox` - BOOL 170 | BOOL to control if the box should be hidden or not. Setting this property to `YES` will essentially turn the checkbox into a check mark. Defaults to `NO`. 171 | 172 | `boxType` - BEMBoxType 173 | The type of box to use. See `BEMBoxType` for possible values. Defaults to `BEMBoxTypeCircle`. 174 |

175 | 176 | `tintColor` - UIColor 177 | The color of the box when the checkbox is Off. 178 | 179 | `onCheckColor` - UIColor 180 | The color of the check mark when it is On. 181 | 182 | `onFillColor` - UIColor 183 | The color of the inside of the box when it is On. 184 | 185 | `onTintColor` - UIColor 186 | The color of the line around the box when it is On. 187 | 188 | ##### Animations 189 | `animationDuration` - CGFloat 190 | The duration in seconds of the animations. Defaults to `0.5`. 191 | 192 | `onAnimationType` - BEMAnimationType 193 | The type of animation to use when the checkbox gets checked. Defaults to `BEMAnimationTypeStroke`. See `BEMAnimationType` bellow for possible values. 194 | 195 | `offAnimationType` - BEMAnimationType 196 | The type of animation to use when the checkbox gets unchecked. Defaults to `BEMAnimationTypeStroke`. See `BEMAnimationType` bellow for possible values. 197 | 198 | `BEMAnimationType` 199 | The possible values for `onAnimationType` and `offAnimationType`. 200 | - `BEMAnimationTypeStroke` 201 |

202 | 203 | - `BEMAnimationTypeFill` 204 |

205 | 206 | - `BEMAnimationTypeBounce` 207 |

208 | 209 | - `BEMAnimationTypeFlat` 210 |

211 | 212 | - `BEMAnimationTypeOneStroke` 213 |

214 | 215 | - `BEMAnimationTypeFade` 216 |

217 | -------------------------------------------------------------------------------- /Sample Project/BEMCheckBox/CheckBox.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMCheckBox.h 3 | // BEMCheckBox 4 | // 5 | // Created by Hardik on 5/8/16. 6 | // Copyright © 2016 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for BEMCheckBox. 12 | FOUNDATION_EXPORT double BEMCheckBoxVersionNumber; 13 | 14 | //! Project version string for BEMCheckBox. 15 | FOUNDATION_EXPORT const unsigned char BEMCheckBoxVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import -------------------------------------------------------------------------------- /Sample Project/BEMCheckBox/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5B677ED523F2B168007FBFC2 /* BEMPathManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B677ED123F2B168007FBFC2 /* BEMPathManager.swift */; platformFilter = ios; }; 11 | 5B677ED623F2B168007FBFC2 /* BEMCheckBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B677ED223F2B168007FBFC2 /* BEMCheckBox.swift */; platformFilter = ios; }; 12 | 5B677ED723F2B168007FBFC2 /* BEMAnimationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B677ED323F2B168007FBFC2 /* BEMAnimationManager.swift */; platformFilter = ios; }; 13 | 5B677ED823F2B168007FBFC2 /* BEMCheckBoxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B677ED423F2B168007FBFC2 /* BEMCheckBoxGroup.swift */; platformFilter = ios; }; 14 | 5B677EF123F2C3B4007FBFC2 /* BEMCheckBox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5643F12B1CDE722C0020E238 /* BEMCheckBox.framework */; }; 15 | 5B677EF223F2C3B4007FBFC2 /* BEMCheckBox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5643F12B1CDE722C0020E238 /* BEMCheckBox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | C32537131B9231780059F394 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C32537121B9231780059F394 /* main.m */; }; 17 | C32537161B9231780059F394 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C32537151B9231780059F394 /* AppDelegate.m */; }; 18 | C325371C1B9231780059F394 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C325371A1B9231780059F394 /* Main.storyboard */; }; 19 | C325371E1B9231780059F394 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C325371D1B9231780059F394 /* Images.xcassets */; }; 20 | C32537211B9231780059F394 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = C325371F1B9231780059F394 /* LaunchScreen.xib */; }; 21 | C325372D1B9231780059F394 /* CheckBoxTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C325372C1B9231780059F394 /* CheckBoxTests.m */; }; 22 | C39F1AB71BAFEAA400E8A023 /* BEMMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C39F1AB61BAFEAA400E8A023 /* BEMMainViewController.m */; }; 23 | C3C066E61DB7002C00178397 /* GroupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C3C066E51DB7002C00178397 /* GroupTests.m */; }; 24 | C3DFB9BA1BBA475B00D2F8B4 /* AnimationManangerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C3DFB9B91BBA475B00D2F8B4 /* AnimationManangerTests.m */; }; 25 | C3DFB9BD1BBD0E2800D2F8B4 /* BEMAnimationsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C3DFB9BC1BBD0E2800D2F8B4 /* BEMAnimationsTableViewController.m */; }; 26 | C3E594901BC220C7005EA38B /* BEMCurrentSetupTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E5948F1BC220C7005EA38B /* BEMCurrentSetupTableViewController.m */; }; 27 | FC76C2451D7A121200EE3AA4 /* CheckBoxUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = FC76C2441D7A121200EE3AA4 /* CheckBoxUITests.m */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXContainerItemProxy section */ 31 | 5B677EF323F2C3B4007FBFC2 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = C32537051B9231780059F394 /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 5643F12A1CDE722C0020E238; 36 | remoteInfo = BEMCheckBox; 37 | }; 38 | C32537271B9231780059F394 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = C32537051B9231780059F394 /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = C325370C1B9231780059F394; 43 | remoteInfo = CheckBox; 44 | }; 45 | FC76C2471D7A121200EE3AA4 /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = C32537051B9231780059F394 /* Project object */; 48 | proxyType = 1; 49 | remoteGlobalIDString = C325370C1B9231780059F394; 50 | remoteInfo = CheckBox; 51 | }; 52 | /* End PBXContainerItemProxy section */ 53 | 54 | /* Begin PBXCopyFilesBuildPhase section */ 55 | 5B677EF523F2C3B4007FBFC2 /* Embed Frameworks */ = { 56 | isa = PBXCopyFilesBuildPhase; 57 | buildActionMask = 2147483647; 58 | dstPath = ""; 59 | dstSubfolderSpec = 10; 60 | files = ( 61 | 5B677EF223F2C3B4007FBFC2 /* BEMCheckBox.framework in Embed Frameworks */, 62 | ); 63 | name = "Embed Frameworks"; 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXCopyFilesBuildPhase section */ 67 | 68 | /* Begin PBXFileReference section */ 69 | 5643F12B1CDE722C0020E238 /* BEMCheckBox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BEMCheckBox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | 5643F12D1CDE722C0020E238 /* CheckBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CheckBox.h; sourceTree = ""; }; 71 | 5643F12F1CDE722C0020E238 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | 5B677ED123F2B168007FBFC2 /* BEMPathManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BEMPathManager.swift; path = ../Classes/BEMPathManager.swift; sourceTree = ""; }; 73 | 5B677ED223F2B168007FBFC2 /* BEMCheckBox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BEMCheckBox.swift; path = ../Classes/BEMCheckBox.swift; sourceTree = ""; }; 74 | 5B677ED323F2B168007FBFC2 /* BEMAnimationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BEMAnimationManager.swift; path = ../Classes/BEMAnimationManager.swift; sourceTree = ""; }; 75 | 5B677ED423F2B168007FBFC2 /* BEMCheckBoxGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BEMCheckBoxGroup.swift; path = ../Classes/BEMCheckBoxGroup.swift; sourceTree = ""; }; 76 | C325370D1B9231780059F394 /* CheckBox.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CheckBox.app; sourceTree = BUILT_PRODUCTS_DIR; }; 77 | C32537111B9231780059F394 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 78 | C32537121B9231780059F394 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 79 | C32537141B9231780059F394 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 80 | C32537151B9231780059F394 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 81 | C325371B1B9231780059F394 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 82 | C325371D1B9231780059F394 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 83 | C32537201B9231780059F394 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 84 | C32537261B9231780059F394 /* CheckBoxTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CheckBoxTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | C325372B1B9231780059F394 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86 | C325372C1B9231780059F394 /* CheckBoxTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CheckBoxTests.m; sourceTree = ""; }; 87 | C39F1AB51BAFEAA400E8A023 /* BEMMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BEMMainViewController.h; sourceTree = ""; }; 88 | C39F1AB61BAFEAA400E8A023 /* BEMMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BEMMainViewController.m; sourceTree = ""; }; 89 | C3C066E51DB7002C00178397 /* GroupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupTests.m; sourceTree = ""; }; 90 | C3DFB9B91BBA475B00D2F8B4 /* AnimationManangerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnimationManangerTests.m; sourceTree = ""; }; 91 | C3DFB9BB1BBD0E2800D2F8B4 /* BEMAnimationsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BEMAnimationsTableViewController.h; sourceTree = ""; }; 92 | C3DFB9BC1BBD0E2800D2F8B4 /* BEMAnimationsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BEMAnimationsTableViewController.m; sourceTree = ""; }; 93 | C3E5948E1BC220C7005EA38B /* BEMCurrentSetupTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BEMCurrentSetupTableViewController.h; sourceTree = ""; }; 94 | C3E5948F1BC220C7005EA38B /* BEMCurrentSetupTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BEMCurrentSetupTableViewController.m; sourceTree = ""; }; 95 | FC76C2421D7A121200EE3AA4 /* CheckBoxUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CheckBoxUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 96 | FC76C2441D7A121200EE3AA4 /* CheckBoxUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CheckBoxUITests.m; sourceTree = ""; }; 97 | FC76C2461D7A121200EE3AA4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 98 | /* End PBXFileReference section */ 99 | 100 | /* Begin PBXFrameworksBuildPhase section */ 101 | 5643F1271CDE722C0020E238 /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | C325370A1B9231780059F394 /* Frameworks */ = { 109 | isa = PBXFrameworksBuildPhase; 110 | buildActionMask = 2147483647; 111 | files = ( 112 | 5B677EF123F2C3B4007FBFC2 /* BEMCheckBox.framework in Frameworks */, 113 | ); 114 | runOnlyForDeploymentPostprocessing = 0; 115 | }; 116 | C32537231B9231780059F394 /* Frameworks */ = { 117 | isa = PBXFrameworksBuildPhase; 118 | buildActionMask = 2147483647; 119 | files = ( 120 | ); 121 | runOnlyForDeploymentPostprocessing = 0; 122 | }; 123 | FC76C23F1D7A121200EE3AA4 /* Frameworks */ = { 124 | isa = PBXFrameworksBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | /* End PBXFrameworksBuildPhase section */ 131 | 132 | /* Begin PBXGroup section */ 133 | 5643F12C1CDE722C0020E238 /* BEMCheckBox */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 5643F12D1CDE722C0020E238 /* CheckBox.h */, 137 | 5643F12F1CDE722C0020E238 /* Info.plist */, 138 | ); 139 | path = BEMCheckBox; 140 | sourceTree = ""; 141 | }; 142 | 5B677ED923F2B28E007FBFC2 /* Frameworks */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | ); 146 | name = Frameworks; 147 | sourceTree = ""; 148 | }; 149 | C32537041B9231780059F394 = { 150 | isa = PBXGroup; 151 | children = ( 152 | C32537361B92318C0059F394 /* Classes */, 153 | C325370F1B9231780059F394 /* CheckBox */, 154 | 5643F12C1CDE722C0020E238 /* BEMCheckBox */, 155 | C32537291B9231780059F394 /* CheckBoxTests */, 156 | FC76C2431D7A121200EE3AA4 /* CheckBoxUITests */, 157 | C325370E1B9231780059F394 /* Products */, 158 | 5B677ED923F2B28E007FBFC2 /* Frameworks */, 159 | ); 160 | sourceTree = ""; 161 | }; 162 | C325370E1B9231780059F394 /* Products */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | C325370D1B9231780059F394 /* CheckBox.app */, 166 | C32537261B9231780059F394 /* CheckBoxTests.xctest */, 167 | 5643F12B1CDE722C0020E238 /* BEMCheckBox.framework */, 168 | FC76C2421D7A121200EE3AA4 /* CheckBoxUITests.xctest */, 169 | ); 170 | name = Products; 171 | sourceTree = ""; 172 | }; 173 | C325370F1B9231780059F394 /* CheckBox */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | C32537141B9231780059F394 /* AppDelegate.h */, 177 | C32537151B9231780059F394 /* AppDelegate.m */, 178 | C325371A1B9231780059F394 /* Main.storyboard */, 179 | C39F1AB51BAFEAA400E8A023 /* BEMMainViewController.h */, 180 | C39F1AB61BAFEAA400E8A023 /* BEMMainViewController.m */, 181 | C3DFB9BB1BBD0E2800D2F8B4 /* BEMAnimationsTableViewController.h */, 182 | C3DFB9BC1BBD0E2800D2F8B4 /* BEMAnimationsTableViewController.m */, 183 | C3E5948E1BC220C7005EA38B /* BEMCurrentSetupTableViewController.h */, 184 | C3E5948F1BC220C7005EA38B /* BEMCurrentSetupTableViewController.m */, 185 | C325371D1B9231780059F394 /* Images.xcassets */, 186 | C325371F1B9231780059F394 /* LaunchScreen.xib */, 187 | C32537101B9231780059F394 /* Supporting Files */, 188 | ); 189 | path = CheckBox; 190 | sourceTree = ""; 191 | }; 192 | C32537101B9231780059F394 /* Supporting Files */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | C32537111B9231780059F394 /* Info.plist */, 196 | C32537121B9231780059F394 /* main.m */, 197 | ); 198 | name = "Supporting Files"; 199 | sourceTree = ""; 200 | }; 201 | C32537291B9231780059F394 /* CheckBoxTests */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | C325372C1B9231780059F394 /* CheckBoxTests.m */, 205 | C3C066E51DB7002C00178397 /* GroupTests.m */, 206 | C3DFB9B91BBA475B00D2F8B4 /* AnimationManangerTests.m */, 207 | C325372A1B9231780059F394 /* Supporting Files */, 208 | ); 209 | path = CheckBoxTests; 210 | sourceTree = ""; 211 | }; 212 | C325372A1B9231780059F394 /* Supporting Files */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | C325372B1B9231780059F394 /* Info.plist */, 216 | ); 217 | name = "Supporting Files"; 218 | sourceTree = ""; 219 | }; 220 | C32537361B92318C0059F394 /* Classes */ = { 221 | isa = PBXGroup; 222 | children = ( 223 | 5B677ED323F2B168007FBFC2 /* BEMAnimationManager.swift */, 224 | 5B677ED223F2B168007FBFC2 /* BEMCheckBox.swift */, 225 | 5B677ED423F2B168007FBFC2 /* BEMCheckBoxGroup.swift */, 226 | 5B677ED123F2B168007FBFC2 /* BEMPathManager.swift */, 227 | ); 228 | name = Classes; 229 | sourceTree = ""; 230 | }; 231 | FC76C2431D7A121200EE3AA4 /* CheckBoxUITests */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | FC76C2441D7A121200EE3AA4 /* CheckBoxUITests.m */, 235 | FC76C2461D7A121200EE3AA4 /* Info.plist */, 236 | ); 237 | path = CheckBoxUITests; 238 | sourceTree = ""; 239 | }; 240 | /* End PBXGroup section */ 241 | 242 | /* Begin PBXHeadersBuildPhase section */ 243 | 5643F1281CDE722C0020E238 /* Headers */ = { 244 | isa = PBXHeadersBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | /* End PBXHeadersBuildPhase section */ 251 | 252 | /* Begin PBXNativeTarget section */ 253 | 5643F12A1CDE722C0020E238 /* BEMCheckBox */ = { 254 | isa = PBXNativeTarget; 255 | buildConfigurationList = 5643F1361CDE722C0020E238 /* Build configuration list for PBXNativeTarget "BEMCheckBox" */; 256 | buildPhases = ( 257 | 5643F1261CDE722C0020E238 /* Sources */, 258 | 5643F1271CDE722C0020E238 /* Frameworks */, 259 | 5643F1281CDE722C0020E238 /* Headers */, 260 | 5643F1291CDE722C0020E238 /* Resources */, 261 | ); 262 | buildRules = ( 263 | ); 264 | dependencies = ( 265 | ); 266 | name = BEMCheckBox; 267 | productName = BEMCheckBox; 268 | productReference = 5643F12B1CDE722C0020E238 /* BEMCheckBox.framework */; 269 | productType = "com.apple.product-type.framework"; 270 | }; 271 | C325370C1B9231780059F394 /* CheckBox */ = { 272 | isa = PBXNativeTarget; 273 | buildConfigurationList = C32537301B9231780059F394 /* Build configuration list for PBXNativeTarget "CheckBox" */; 274 | buildPhases = ( 275 | C32537091B9231780059F394 /* Sources */, 276 | C325370A1B9231780059F394 /* Frameworks */, 277 | C325370B1B9231780059F394 /* Resources */, 278 | 5B677EF523F2C3B4007FBFC2 /* Embed Frameworks */, 279 | ); 280 | buildRules = ( 281 | ); 282 | dependencies = ( 283 | 5B677EF423F2C3B4007FBFC2 /* PBXTargetDependency */, 284 | ); 285 | name = CheckBox; 286 | productName = CheckBox; 287 | productReference = C325370D1B9231780059F394 /* CheckBox.app */; 288 | productType = "com.apple.product-type.application"; 289 | }; 290 | C32537251B9231780059F394 /* CheckBoxTests */ = { 291 | isa = PBXNativeTarget; 292 | buildConfigurationList = C32537331B9231780059F394 /* Build configuration list for PBXNativeTarget "CheckBoxTests" */; 293 | buildPhases = ( 294 | C32537221B9231780059F394 /* Sources */, 295 | C32537231B9231780059F394 /* Frameworks */, 296 | C32537241B9231780059F394 /* Resources */, 297 | ); 298 | buildRules = ( 299 | ); 300 | dependencies = ( 301 | C32537281B9231780059F394 /* PBXTargetDependency */, 302 | ); 303 | name = CheckBoxTests; 304 | productName = CheckBoxTests; 305 | productReference = C32537261B9231780059F394 /* CheckBoxTests.xctest */; 306 | productType = "com.apple.product-type.bundle.unit-test"; 307 | }; 308 | FC76C2411D7A121200EE3AA4 /* CheckBoxUITests */ = { 309 | isa = PBXNativeTarget; 310 | buildConfigurationList = FC76C24B1D7A121200EE3AA4 /* Build configuration list for PBXNativeTarget "CheckBoxUITests" */; 311 | buildPhases = ( 312 | FC76C23E1D7A121200EE3AA4 /* Sources */, 313 | FC76C23F1D7A121200EE3AA4 /* Frameworks */, 314 | FC76C2401D7A121200EE3AA4 /* Resources */, 315 | ); 316 | buildRules = ( 317 | ); 318 | dependencies = ( 319 | FC76C2481D7A121200EE3AA4 /* PBXTargetDependency */, 320 | ); 321 | name = CheckBoxUITests; 322 | productName = CheckBoxUITests; 323 | productReference = FC76C2421D7A121200EE3AA4 /* CheckBoxUITests.xctest */; 324 | productType = "com.apple.product-type.bundle.ui-testing"; 325 | }; 326 | /* End PBXNativeTarget section */ 327 | 328 | /* Begin PBXProject section */ 329 | C32537051B9231780059F394 /* Project object */ = { 330 | isa = PBXProject; 331 | attributes = { 332 | LastUpgradeCheck = 0800; 333 | ORGANIZATIONNAME = "Boris Emorine"; 334 | TargetAttributes = { 335 | 5643F12A1CDE722C0020E238 = { 336 | CreatedOnToolsVersion = 7.3.1; 337 | LastSwiftMigration = 1120; 338 | }; 339 | C325370C1B9231780059F394 = { 340 | CreatedOnToolsVersion = 6.4; 341 | LastSwiftMigration = 1120; 342 | }; 343 | C32537251B9231780059F394 = { 344 | CreatedOnToolsVersion = 6.4; 345 | TestTargetID = C325370C1B9231780059F394; 346 | }; 347 | FC76C2411D7A121200EE3AA4 = { 348 | CreatedOnToolsVersion = 8.0; 349 | ProvisioningStyle = Automatic; 350 | TestTargetID = C325370C1B9231780059F394; 351 | }; 352 | }; 353 | }; 354 | buildConfigurationList = C32537081B9231780059F394 /* Build configuration list for PBXProject "CheckBox" */; 355 | compatibilityVersion = "Xcode 3.2"; 356 | developmentRegion = English; 357 | hasScannedForEncodings = 0; 358 | knownRegions = ( 359 | English, 360 | en, 361 | Base, 362 | ); 363 | mainGroup = C32537041B9231780059F394; 364 | productRefGroup = C325370E1B9231780059F394 /* Products */; 365 | projectDirPath = ""; 366 | projectRoot = ""; 367 | targets = ( 368 | C325370C1B9231780059F394 /* CheckBox */, 369 | C32537251B9231780059F394 /* CheckBoxTests */, 370 | FC76C2411D7A121200EE3AA4 /* CheckBoxUITests */, 371 | 5643F12A1CDE722C0020E238 /* BEMCheckBox */, 372 | ); 373 | }; 374 | /* End PBXProject section */ 375 | 376 | /* Begin PBXResourcesBuildPhase section */ 377 | 5643F1291CDE722C0020E238 /* Resources */ = { 378 | isa = PBXResourcesBuildPhase; 379 | buildActionMask = 2147483647; 380 | files = ( 381 | ); 382 | runOnlyForDeploymentPostprocessing = 0; 383 | }; 384 | C325370B1B9231780059F394 /* Resources */ = { 385 | isa = PBXResourcesBuildPhase; 386 | buildActionMask = 2147483647; 387 | files = ( 388 | C325371C1B9231780059F394 /* Main.storyboard in Resources */, 389 | C32537211B9231780059F394 /* LaunchScreen.xib in Resources */, 390 | C325371E1B9231780059F394 /* Images.xcassets in Resources */, 391 | ); 392 | runOnlyForDeploymentPostprocessing = 0; 393 | }; 394 | C32537241B9231780059F394 /* Resources */ = { 395 | isa = PBXResourcesBuildPhase; 396 | buildActionMask = 2147483647; 397 | files = ( 398 | ); 399 | runOnlyForDeploymentPostprocessing = 0; 400 | }; 401 | FC76C2401D7A121200EE3AA4 /* Resources */ = { 402 | isa = PBXResourcesBuildPhase; 403 | buildActionMask = 2147483647; 404 | files = ( 405 | ); 406 | runOnlyForDeploymentPostprocessing = 0; 407 | }; 408 | /* End PBXResourcesBuildPhase section */ 409 | 410 | /* Begin PBXSourcesBuildPhase section */ 411 | 5643F1261CDE722C0020E238 /* Sources */ = { 412 | isa = PBXSourcesBuildPhase; 413 | buildActionMask = 2147483647; 414 | files = ( 415 | 5B677ED723F2B168007FBFC2 /* BEMAnimationManager.swift in Sources */, 416 | 5B677ED823F2B168007FBFC2 /* BEMCheckBoxGroup.swift in Sources */, 417 | 5B677ED523F2B168007FBFC2 /* BEMPathManager.swift in Sources */, 418 | 5B677ED623F2B168007FBFC2 /* BEMCheckBox.swift in Sources */, 419 | ); 420 | runOnlyForDeploymentPostprocessing = 0; 421 | }; 422 | C32537091B9231780059F394 /* Sources */ = { 423 | isa = PBXSourcesBuildPhase; 424 | buildActionMask = 2147483647; 425 | files = ( 426 | C39F1AB71BAFEAA400E8A023 /* BEMMainViewController.m in Sources */, 427 | C3DFB9BD1BBD0E2800D2F8B4 /* BEMAnimationsTableViewController.m in Sources */, 428 | C32537161B9231780059F394 /* AppDelegate.m in Sources */, 429 | C32537131B9231780059F394 /* main.m in Sources */, 430 | C3E594901BC220C7005EA38B /* BEMCurrentSetupTableViewController.m in Sources */, 431 | ); 432 | runOnlyForDeploymentPostprocessing = 0; 433 | }; 434 | C32537221B9231780059F394 /* Sources */ = { 435 | isa = PBXSourcesBuildPhase; 436 | buildActionMask = 2147483647; 437 | files = ( 438 | C3C066E61DB7002C00178397 /* GroupTests.m in Sources */, 439 | C325372D1B9231780059F394 /* CheckBoxTests.m in Sources */, 440 | C3DFB9BA1BBA475B00D2F8B4 /* AnimationManangerTests.m in Sources */, 441 | ); 442 | runOnlyForDeploymentPostprocessing = 0; 443 | }; 444 | FC76C23E1D7A121200EE3AA4 /* Sources */ = { 445 | isa = PBXSourcesBuildPhase; 446 | buildActionMask = 2147483647; 447 | files = ( 448 | FC76C2451D7A121200EE3AA4 /* CheckBoxUITests.m in Sources */, 449 | ); 450 | runOnlyForDeploymentPostprocessing = 0; 451 | }; 452 | /* End PBXSourcesBuildPhase section */ 453 | 454 | /* Begin PBXTargetDependency section */ 455 | 5B677EF423F2C3B4007FBFC2 /* PBXTargetDependency */ = { 456 | isa = PBXTargetDependency; 457 | target = 5643F12A1CDE722C0020E238 /* BEMCheckBox */; 458 | targetProxy = 5B677EF323F2C3B4007FBFC2 /* PBXContainerItemProxy */; 459 | }; 460 | C32537281B9231780059F394 /* PBXTargetDependency */ = { 461 | isa = PBXTargetDependency; 462 | target = C325370C1B9231780059F394 /* CheckBox */; 463 | targetProxy = C32537271B9231780059F394 /* PBXContainerItemProxy */; 464 | }; 465 | FC76C2481D7A121200EE3AA4 /* PBXTargetDependency */ = { 466 | isa = PBXTargetDependency; 467 | target = C325370C1B9231780059F394 /* CheckBox */; 468 | targetProxy = FC76C2471D7A121200EE3AA4 /* PBXContainerItemProxy */; 469 | }; 470 | /* End PBXTargetDependency section */ 471 | 472 | /* Begin PBXVariantGroup section */ 473 | C325371A1B9231780059F394 /* Main.storyboard */ = { 474 | isa = PBXVariantGroup; 475 | children = ( 476 | C325371B1B9231780059F394 /* Base */, 477 | ); 478 | name = Main.storyboard; 479 | sourceTree = ""; 480 | }; 481 | C325371F1B9231780059F394 /* LaunchScreen.xib */ = { 482 | isa = PBXVariantGroup; 483 | children = ( 484 | C32537201B9231780059F394 /* Base */, 485 | ); 486 | name = LaunchScreen.xib; 487 | sourceTree = ""; 488 | }; 489 | /* End PBXVariantGroup section */ 490 | 491 | /* Begin XCBuildConfiguration section */ 492 | 5643F1341CDE722C0020E238 /* Debug */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | CLANG_ANALYZER_NONNULL = YES; 496 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 497 | CURRENT_PROJECT_VERSION = 1; 498 | DEBUG_INFORMATION_FORMAT = dwarf; 499 | DEFINES_MODULE = YES; 500 | DYLIB_COMPATIBILITY_VERSION = 1; 501 | DYLIB_CURRENT_VERSION = 1; 502 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 503 | INFOPLIST_FILE = BEMCheckBox/Info.plist; 504 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 505 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 506 | LD_RUNPATH_SEARCH_PATHS = ( 507 | "$(inherited)", 508 | "@executable_path/Frameworks", 509 | "@loader_path/Frameworks", 510 | ); 511 | PRODUCT_BUNDLE_IDENTIFIER = BEM.CheckBox; 512 | PRODUCT_NAME = "$(TARGET_NAME)"; 513 | SKIP_INSTALL = YES; 514 | SUPPORTS_MACCATALYST = NO; 515 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 516 | SWIFT_VERSION = 5.0; 517 | TARGETED_DEVICE_FAMILY = "1,2"; 518 | VERSIONING_SYSTEM = "apple-generic"; 519 | VERSION_INFO_PREFIX = ""; 520 | }; 521 | name = Debug; 522 | }; 523 | 5643F1351CDE722C0020E238 /* Release */ = { 524 | isa = XCBuildConfiguration; 525 | buildSettings = { 526 | CLANG_ANALYZER_NONNULL = YES; 527 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 528 | CURRENT_PROJECT_VERSION = 1; 529 | DEFINES_MODULE = YES; 530 | DYLIB_COMPATIBILITY_VERSION = 1; 531 | DYLIB_CURRENT_VERSION = 1; 532 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 533 | INFOPLIST_FILE = BEMCheckBox/Info.plist; 534 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 535 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 536 | LD_RUNPATH_SEARCH_PATHS = ( 537 | "$(inherited)", 538 | "@executable_path/Frameworks", 539 | "@loader_path/Frameworks", 540 | ); 541 | PRODUCT_BUNDLE_IDENTIFIER = BEM.CheckBox; 542 | PRODUCT_NAME = "$(TARGET_NAME)"; 543 | SKIP_INSTALL = YES; 544 | SUPPORTS_MACCATALYST = NO; 545 | SWIFT_VERSION = 5.0; 546 | TARGETED_DEVICE_FAMILY = "1,2"; 547 | VERSIONING_SYSTEM = "apple-generic"; 548 | VERSION_INFO_PREFIX = ""; 549 | }; 550 | name = Release; 551 | }; 552 | C325372E1B9231780059F394 /* Debug */ = { 553 | isa = XCBuildConfiguration; 554 | buildSettings = { 555 | ALWAYS_SEARCH_USER_PATHS = NO; 556 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 557 | CLANG_CXX_LIBRARY = "libc++"; 558 | CLANG_ENABLE_MODULES = YES; 559 | CLANG_ENABLE_OBJC_ARC = YES; 560 | CLANG_WARN_BOOL_CONVERSION = YES; 561 | CLANG_WARN_CONSTANT_CONVERSION = YES; 562 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 563 | CLANG_WARN_EMPTY_BODY = YES; 564 | CLANG_WARN_ENUM_CONVERSION = YES; 565 | CLANG_WARN_INFINITE_RECURSION = YES; 566 | CLANG_WARN_INT_CONVERSION = YES; 567 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 568 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 569 | CLANG_WARN_UNREACHABLE_CODE = YES; 570 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 571 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 572 | COPY_PHASE_STRIP = NO; 573 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 574 | ENABLE_STRICT_OBJC_MSGSEND = YES; 575 | ENABLE_TESTABILITY = YES; 576 | GCC_C_LANGUAGE_STANDARD = gnu99; 577 | GCC_DYNAMIC_NO_PIC = NO; 578 | GCC_NO_COMMON_BLOCKS = YES; 579 | GCC_OPTIMIZATION_LEVEL = 0; 580 | GCC_PREPROCESSOR_DEFINITIONS = ( 581 | "DEBUG=1", 582 | "$(inherited)", 583 | ); 584 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 585 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 586 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 587 | GCC_WARN_UNDECLARED_SELECTOR = YES; 588 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 589 | GCC_WARN_UNUSED_FUNCTION = YES; 590 | GCC_WARN_UNUSED_VARIABLE = YES; 591 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 592 | MTL_ENABLE_DEBUG_INFO = YES; 593 | ONLY_ACTIVE_ARCH = YES; 594 | SDKROOT = iphoneos; 595 | }; 596 | name = Debug; 597 | }; 598 | C325372F1B9231780059F394 /* Release */ = { 599 | isa = XCBuildConfiguration; 600 | buildSettings = { 601 | ALWAYS_SEARCH_USER_PATHS = NO; 602 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 603 | CLANG_CXX_LIBRARY = "libc++"; 604 | CLANG_ENABLE_MODULES = YES; 605 | CLANG_ENABLE_OBJC_ARC = YES; 606 | CLANG_WARN_BOOL_CONVERSION = YES; 607 | CLANG_WARN_CONSTANT_CONVERSION = YES; 608 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 609 | CLANG_WARN_EMPTY_BODY = YES; 610 | CLANG_WARN_ENUM_CONVERSION = YES; 611 | CLANG_WARN_INFINITE_RECURSION = YES; 612 | CLANG_WARN_INT_CONVERSION = YES; 613 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 614 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 615 | CLANG_WARN_UNREACHABLE_CODE = YES; 616 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 617 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 618 | COPY_PHASE_STRIP = NO; 619 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 620 | ENABLE_NS_ASSERTIONS = NO; 621 | ENABLE_STRICT_OBJC_MSGSEND = YES; 622 | GCC_C_LANGUAGE_STANDARD = gnu99; 623 | GCC_NO_COMMON_BLOCKS = YES; 624 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 625 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 626 | GCC_WARN_UNDECLARED_SELECTOR = YES; 627 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 628 | GCC_WARN_UNUSED_FUNCTION = YES; 629 | GCC_WARN_UNUSED_VARIABLE = YES; 630 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 631 | MTL_ENABLE_DEBUG_INFO = NO; 632 | SDKROOT = iphoneos; 633 | VALIDATE_PRODUCT = YES; 634 | }; 635 | name = Release; 636 | }; 637 | C32537311B9231780059F394 /* Debug */ = { 638 | isa = XCBuildConfiguration; 639 | buildSettings = { 640 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 641 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 642 | CLANG_ENABLE_MODULES = YES; 643 | INFOPLIST_FILE = CheckBox/Info.plist; 644 | LD_RUNPATH_SEARCH_PATHS = ( 645 | "$(inherited)", 646 | "@executable_path/Frameworks", 647 | ); 648 | PRODUCT_BUNDLE_IDENTIFIER = "BEM.$(PRODUCT_NAME:rfc1034identifier).exampleApp"; 649 | PRODUCT_NAME = "$(TARGET_NAME)"; 650 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 651 | SWIFT_VERSION = 5.0; 652 | }; 653 | name = Debug; 654 | }; 655 | C32537321B9231780059F394 /* Release */ = { 656 | isa = XCBuildConfiguration; 657 | buildSettings = { 658 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 659 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 660 | CLANG_ENABLE_MODULES = YES; 661 | INFOPLIST_FILE = CheckBox/Info.plist; 662 | LD_RUNPATH_SEARCH_PATHS = ( 663 | "$(inherited)", 664 | "@executable_path/Frameworks", 665 | ); 666 | PRODUCT_BUNDLE_IDENTIFIER = "BEM.$(PRODUCT_NAME:rfc1034identifier).exampleApp"; 667 | PRODUCT_NAME = "$(TARGET_NAME)"; 668 | SWIFT_VERSION = 5.0; 669 | }; 670 | name = Release; 671 | }; 672 | C32537341B9231780059F394 /* Debug */ = { 673 | isa = XCBuildConfiguration; 674 | buildSettings = { 675 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 676 | BUNDLE_LOADER = "$(TEST_HOST)"; 677 | GCC_PREPROCESSOR_DEFINITIONS = ( 678 | "DEBUG=1", 679 | "$(inherited)", 680 | ); 681 | INFOPLIST_FILE = CheckBoxTests/Info.plist; 682 | LD_RUNPATH_SEARCH_PATHS = ( 683 | "$(inherited)", 684 | "@executable_path/Frameworks", 685 | "@loader_path/Frameworks", 686 | ); 687 | PRODUCT_BUNDLE_IDENTIFIER = "BEM.$(PRODUCT_NAME:rfc1034identifier)"; 688 | PRODUCT_NAME = "$(TARGET_NAME)"; 689 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CheckBox.app/CheckBox"; 690 | }; 691 | name = Debug; 692 | }; 693 | C32537351B9231780059F394 /* Release */ = { 694 | isa = XCBuildConfiguration; 695 | buildSettings = { 696 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 697 | BUNDLE_LOADER = "$(TEST_HOST)"; 698 | INFOPLIST_FILE = CheckBoxTests/Info.plist; 699 | LD_RUNPATH_SEARCH_PATHS = ( 700 | "$(inherited)", 701 | "@executable_path/Frameworks", 702 | "@loader_path/Frameworks", 703 | ); 704 | PRODUCT_BUNDLE_IDENTIFIER = "BEM.$(PRODUCT_NAME:rfc1034identifier)"; 705 | PRODUCT_NAME = "$(TARGET_NAME)"; 706 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CheckBox.app/CheckBox"; 707 | }; 708 | name = Release; 709 | }; 710 | FC76C2491D7A121200EE3AA4 /* Debug */ = { 711 | isa = XCBuildConfiguration; 712 | buildSettings = { 713 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 714 | CLANG_ANALYZER_NONNULL = YES; 715 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 716 | CLANG_WARN_INFINITE_RECURSION = YES; 717 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 718 | DEBUG_INFORMATION_FORMAT = dwarf; 719 | INFOPLIST_FILE = CheckBoxUITests/Info.plist; 720 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 721 | LD_RUNPATH_SEARCH_PATHS = ( 722 | "$(inherited)", 723 | "@executable_path/Frameworks", 724 | "@loader_path/Frameworks", 725 | ); 726 | PRODUCT_BUNDLE_IDENTIFIER = borisemorine.CheckBoxUITests; 727 | PRODUCT_NAME = "$(TARGET_NAME)"; 728 | TEST_TARGET_NAME = CheckBox; 729 | }; 730 | name = Debug; 731 | }; 732 | FC76C24A1D7A121200EE3AA4 /* Release */ = { 733 | isa = XCBuildConfiguration; 734 | buildSettings = { 735 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 736 | CLANG_ANALYZER_NONNULL = YES; 737 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 738 | CLANG_WARN_INFINITE_RECURSION = YES; 739 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 740 | INFOPLIST_FILE = CheckBoxUITests/Info.plist; 741 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 742 | LD_RUNPATH_SEARCH_PATHS = ( 743 | "$(inherited)", 744 | "@executable_path/Frameworks", 745 | "@loader_path/Frameworks", 746 | ); 747 | PRODUCT_BUNDLE_IDENTIFIER = borisemorine.CheckBoxUITests; 748 | PRODUCT_NAME = "$(TARGET_NAME)"; 749 | TEST_TARGET_NAME = CheckBox; 750 | }; 751 | name = Release; 752 | }; 753 | /* End XCBuildConfiguration section */ 754 | 755 | /* Begin XCConfigurationList section */ 756 | 5643F1361CDE722C0020E238 /* Build configuration list for PBXNativeTarget "BEMCheckBox" */ = { 757 | isa = XCConfigurationList; 758 | buildConfigurations = ( 759 | 5643F1341CDE722C0020E238 /* Debug */, 760 | 5643F1351CDE722C0020E238 /* Release */, 761 | ); 762 | defaultConfigurationIsVisible = 0; 763 | defaultConfigurationName = Release; 764 | }; 765 | C32537081B9231780059F394 /* Build configuration list for PBXProject "CheckBox" */ = { 766 | isa = XCConfigurationList; 767 | buildConfigurations = ( 768 | C325372E1B9231780059F394 /* Debug */, 769 | C325372F1B9231780059F394 /* Release */, 770 | ); 771 | defaultConfigurationIsVisible = 0; 772 | defaultConfigurationName = Release; 773 | }; 774 | C32537301B9231780059F394 /* Build configuration list for PBXNativeTarget "CheckBox" */ = { 775 | isa = XCConfigurationList; 776 | buildConfigurations = ( 777 | C32537311B9231780059F394 /* Debug */, 778 | C32537321B9231780059F394 /* Release */, 779 | ); 780 | defaultConfigurationIsVisible = 0; 781 | defaultConfigurationName = Release; 782 | }; 783 | C32537331B9231780059F394 /* Build configuration list for PBXNativeTarget "CheckBoxTests" */ = { 784 | isa = XCConfigurationList; 785 | buildConfigurations = ( 786 | C32537341B9231780059F394 /* Debug */, 787 | C32537351B9231780059F394 /* Release */, 788 | ); 789 | defaultConfigurationIsVisible = 0; 790 | defaultConfigurationName = Release; 791 | }; 792 | FC76C24B1D7A121200EE3AA4 /* Build configuration list for PBXNativeTarget "CheckBoxUITests" */ = { 793 | isa = XCConfigurationList; 794 | buildConfigurations = ( 795 | FC76C2491D7A121200EE3AA4 /* Debug */, 796 | FC76C24A1D7A121200EE3AA4 /* Release */, 797 | ); 798 | defaultConfigurationIsVisible = 0; 799 | defaultConfigurationName = Release; 800 | }; 801 | /* End XCConfigurationList section */ 802 | }; 803 | rootObject = C32537051B9231780059F394 /* Project object */; 804 | } 805 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/project.xcworkspace/xcshareddata/CheckBox.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | D2CA03E9-13CD-4250-9470-315173FA2E88 9 | IDESourceControlProjectName 10 | project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 375074DF4A073CA906B8C422E94433ECCC0AE38B 14 | https://github.com/Boris-Em/BEMCheckBox.git 15 | 16 | IDESourceControlProjectPath 17 | Sample Project/CheckBox.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 375074DF4A073CA906B8C422E94433ECCC0AE38B 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/Boris-Em/BEMCheckBox.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 375074DF4A073CA906B8C422E94433ECCC0AE38B 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 375074DF4A073CA906B8C422E94433ECCC0AE38B 36 | IDESourceControlWCCName 37 | BEMCheckBox 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/project.xcworkspace/xcuserdata/Bobo.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/Sample Project/CheckBox.xcodeproj/project.xcworkspace/xcuserdata/Bobo.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/xcshareddata/xcschemes/BEMCheckBox.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/xcshareddata/xcschemes/CheckBox.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 57 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 88 | 90 | 96 | 97 | 98 | 99 | 100 | 101 | 107 | 109 | 115 | 116 | 117 | 118 | 120 | 121 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/xcshareddata/xcschemes/CheckBoxTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 57 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 88 | 90 | 96 | 97 | 98 | 99 | 100 | 101 | 107 | 108 | 114 | 115 | 116 | 117 | 119 | 120 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/xcuserdata/Bobo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Sample Project/CheckBox.xcodeproj/xcuserdata/Bobo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CheckBox.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | CheckBoxTests.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 5643F12A1CDE722C0020E238 21 | 22 | primary 23 | 24 | 25 | C325370C1B9231780059F394 26 | 27 | primary 28 | 29 | 30 | C32537251B9231780059F394 31 | 32 | primary 33 | 34 | 35 | FC76C2411D7A121200EE3AA4 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CheckBox 4 | // 5 | // Created by Bobo on 8/29/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CheckBox 4 | // 5 | // Created by Bobo on 8/29/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/BEMAnimationsTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMAnimationsTableViewController.h 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/30/15. 6 | // Copyright © 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | @import BEMCheckBox; 11 | 12 | @protocol BEMAnimationsTableViewDelegate 13 | 14 | @required 15 | - (void)didSelectAnimationType:(BEMAnimationType)animationType; 16 | 17 | @end 18 | 19 | @interface BEMAnimationsTableViewController : UITableViewController 20 | 21 | @property (weak, nonatomic) id delegate; 22 | 23 | @property (nonatomic) BEMAnimationType selectedAnimation; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/BEMAnimationsTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BEMAnimationsTableViewController.m 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/30/15. 6 | // Copyright © 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import "BEMAnimationsTableViewController.h" 10 | 11 | @interface BEMAnimationsTableViewController () 12 | 13 | @end 14 | 15 | @implementation BEMAnimationsTableViewController 16 | 17 | #pragma mark View Controller Life Cycle 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | } 21 | 22 | - (void)viewWillAppear:(BOOL)animated { 23 | [super viewWillAppear:animated]; 24 | 25 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.selectedAnimation inSection:0]; 26 | UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; 27 | cell.accessoryType = UITableViewCellAccessoryCheckmark; 28 | } 29 | 30 | #pragma mark UITableView Delegate 31 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 32 | [self.delegate didSelectAnimationType:indexPath.row]; 33 | [self.navigationController popViewControllerAnimated:YES]; 34 | } 35 | 36 | - (void)didReceiveMemoryWarning { 37 | [super didReceiveMemoryWarning]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/BEMCurrentSetupTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMCurrentSetupTableViewController.h 3 | // CheckBox 4 | // 5 | // Created by Bobo on 10/4/15. 6 | // Copyright © 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | @import BEMCheckBox; 11 | 12 | @interface BEMCurrentSetupTableViewController : UITableViewController 13 | 14 | @property (strong, nonatomic) BEMCheckBox *checkBox; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/BEMCurrentSetupTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BEMCurrentSetupTableViewController.m 3 | // CheckBox 4 | // 5 | // Created by Bobo on 10/4/15. 6 | // Copyright © 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import "BEMCurrentSetupTableViewController.h" 10 | 11 | @interface BEMCurrentSetupTableViewController () 12 | 13 | @property (weak, nonatomic) IBOutlet UILabel *onPropertyValueLabel; 14 | @property (weak, nonatomic) IBOutlet UILabel *lineWidthPropertyValueLabel; 15 | @property (weak, nonatomic) IBOutlet UILabel *animationDurationPropertyValueLabel; 16 | @property (weak, nonatomic) IBOutlet UILabel *hideBoxPropertyValueLabel; 17 | @property (weak, nonatomic) IBOutlet UILabel *onTintColorPropertyLabel; 18 | @property (weak, nonatomic) IBOutlet UILabel *onFillColorPropertyLabel; 19 | @property (weak, nonatomic) IBOutlet UILabel *onCheckColorPropertyLabel; 20 | @property (weak, nonatomic) IBOutlet UILabel *tintColorPropertyLabel; 21 | @property (weak, nonatomic) IBOutlet UILabel *boxTypePropertyValueLabel; 22 | @property (weak, nonatomic) IBOutlet UILabel *onAnimationTypePropertyValueLabel; 23 | @property (weak, nonatomic) IBOutlet UILabel *offAnimationTypePropertyValueLabel; 24 | 25 | @end 26 | 27 | @implementation BEMCurrentSetupTableViewController 28 | 29 | - (void)viewDidLoad { 30 | [super viewDidLoad]; 31 | 32 | self.onPropertyValueLabel.text = self.checkBox.on ? @"YES" : @"NO"; 33 | self.lineWidthPropertyValueLabel.text = [NSString stringWithFormat:@"%.1f", self.checkBox.lineWidth]; 34 | self.animationDurationPropertyValueLabel.text = [NSString stringWithFormat:@"%.2f", self.checkBox.animationDuration]; 35 | self.hideBoxPropertyValueLabel.text = self.checkBox.hideBox ? @"YES" : @"NO"; 36 | 37 | CGFloat red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0; 38 | [self.checkBox.onTintColor getRed:&red green:&green blue:&blue alpha:&alpha]; 39 | self.onTintColorPropertyLabel.text = [NSString stringWithFormat:@"R:%.0f - G:%.0f - B:%.0f", red * 255.0, green * 255.0, blue * 255.0]; 40 | 41 | [self.checkBox.onFillColor getRed:&red green:&green blue:&blue alpha:&alpha]; 42 | self.onFillColorPropertyLabel.text = [NSString stringWithFormat:@"R:%.0f - G:%.0f - B:%.0f", red * 255.0, green * 255.0, blue * 255.0]; 43 | 44 | [self.checkBox.onCheckColor getRed:&red green:&green blue:&blue alpha:&alpha]; 45 | self.onCheckColorPropertyLabel.text = [NSString stringWithFormat:@"R:%.0f - G:%.0f - B:%.0f", red * 255.0, green * 255.0, blue * 255.0]; 46 | 47 | [self.checkBox.tintColor getRed:&red green:&green blue:&blue alpha:&alpha]; 48 | self.tintColorPropertyLabel.text = [NSString stringWithFormat:@"R:%.0f - G:%.0f - B:%.0f", red * 255.0, green * 255.0, blue * 255.0]; 49 | 50 | self.boxTypePropertyValueLabel.text = self.checkBox.boxType ? @"BEMBoxTypeSquare" : @"BEMBoxTypeCircle"; 51 | self.onAnimationTypePropertyValueLabel.text = [self stringForAnimationType:self.checkBox.onAnimationType]; 52 | self.offAnimationTypePropertyValueLabel.text = [self stringForAnimationType:self.checkBox.offAnimationType]; 53 | } 54 | 55 | #pragma mark Helper Methods 56 | - (NSString *)stringForAnimationType:(BEMAnimationType)animationType { 57 | switch (animationType) { 58 | case BEMAnimationTypeBounce: 59 | return @"BEMAnimationTypeBounce"; 60 | break; 61 | case BEMAnimationTypeFill: 62 | return @"BEMAnimationTypeFill"; 63 | break; 64 | case BEMAnimationTypeFlat: 65 | return @"BEMAnimationTypeFlat"; 66 | break; 67 | case BEMAnimationTypeOneStroke: 68 | return @"BEMAnimationTypeOneStroke"; 69 | break; 70 | case BEMAnimationTypeStroke: 71 | return @"BEMAnimationTypeStroke"; 72 | break; 73 | 74 | default: 75 | return @"BEMAnimationTypeFade"; 76 | break; 77 | } 78 | } 79 | 80 | - (void)didReceiveMemoryWarning { 81 | [super didReceiveMemoryWarning]; 82 | // Dispose of any resources that can be recreated. 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/BEMMainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMMainViewController.h 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/21/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "BEMAnimationsTableViewController.h" 11 | @import BEMCheckBox; 12 | 13 | @interface BEMMainViewController : UIViewController 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/BEMMainViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BEMMainViewController.m 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/21/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import "BEMMainViewController.h" 10 | #import "BEMCurrentSetupTableViewController.h" 11 | 12 | @interface BEMMainViewController () 13 | 14 | @property (strong, nonatomic) IBOutlet BEMCheckBox *checkBox; 15 | 16 | @property (strong, nonatomic) IBOutlet UISegmentedControl *drawTypeSegmentedControl; 17 | 18 | @property (strong, nonatomic) IBOutlet UIButton *animationButton; 19 | 20 | @end 21 | 22 | @implementation BEMMainViewController 23 | 24 | #pragma mark View Controller Life Cycle 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | 28 | self.checkBox.onAnimationType = BEMAnimationTypeBounce; 29 | self.checkBox.offAnimationType = BEMAnimationTypeBounce; 30 | 31 | self.animationButton.layer.cornerRadius = 5.0; 32 | self.animationButton.layer.borderColor = [UIColor whiteColor].CGColor; 33 | self.animationButton.layer.borderWidth = 1.0; 34 | } 35 | 36 | - (void)didReceiveMemoryWarning { 37 | [super didReceiveMemoryWarning]; 38 | // Dispose of any resources that can be recreated. 39 | } 40 | 41 | 42 | #pragma mark Actions 43 | - (IBAction)didDragLineWidthSlider:(UISlider *)slider { 44 | self.checkBox.lineWidth = slider.value; 45 | } 46 | 47 | - (IBAction)didDragAnimationSpeedSlider:(UISlider *)slider { 48 | self.checkBox.animationDuration = slider.value; 49 | } 50 | 51 | - (IBAction)didTapOnBoxTypeSegmentedControl:(UISegmentedControl *)segmentedControl { 52 | self.checkBox.boxType = (segmentedControl.selectedSegmentIndex == 0) ?BEMBoxTypeCircle : BEMBoxTypeSquare; 53 | } 54 | 55 | - (IBAction)didTapOnDrawTypeSegmentedControl:(UISegmentedControl *)segmentedControl { 56 | switch (segmentedControl.selectedSegmentIndex) { 57 | case 0: 58 | self.checkBox.tintColor = [UIColor lightGrayColor]; 59 | self.checkBox.onTintColor = [UIColor colorWithRed:0 green:122.0/255.0 blue:255/255 alpha:1]; 60 | self.checkBox.onFillColor = [UIColor clearColor]; 61 | self.checkBox.onCheckColor = [UIColor colorWithRed:0 green:122.0/255.0 blue:255/255 alpha:1]; 62 | break; 63 | 64 | default: 65 | self.checkBox.tintColor = [UIColor lightGrayColor]; 66 | self.checkBox.onTintColor = [UIColor colorWithRed:0 green:122.0/255.0 blue:255/255 alpha:1]; 67 | self.checkBox.onFillColor = [UIColor colorWithRed:0 green:122.0/255.0 blue:255/255 alpha:1]; 68 | self.checkBox.onCheckColor = [UIColor whiteColor]; 69 | break; 70 | } 71 | } 72 | 73 | #pragma mark BEMAnimationsTableViewDelegate 74 | - (void)didSelectAnimationType:(BEMAnimationType)animationType { 75 | self.checkBox.onAnimationType = animationType; 76 | self.checkBox.offAnimationType = animationType; 77 | 78 | if (animationType == BEMAnimationTypeStroke || animationType == BEMAnimationTypeOneStroke) { 79 | self.drawTypeSegmentedControl.selectedSegmentIndex = 0; 80 | [self.drawTypeSegmentedControl sendActionsForControlEvents:UIControlEventValueChanged]; 81 | self.drawTypeSegmentedControl.enabled = NO; 82 | } else if (animationType == BEMAnimationTypeFill) { 83 | self.drawTypeSegmentedControl.selectedSegmentIndex = 1; 84 | [self.drawTypeSegmentedControl sendActionsForControlEvents:UIControlEventValueChanged]; 85 | self.drawTypeSegmentedControl.enabled = NO; 86 | } else { 87 | self.drawTypeSegmentedControl.enabled = YES; 88 | } 89 | } 90 | 91 | #pragma mark Navigation 92 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 93 | if ([segue.identifier isEqualToString:@"toAnimationSelection"]) { 94 | BEMAnimationsTableViewController *destVC = (BEMAnimationsTableViewController *)segue.destinationViewController; 95 | destVC.delegate = self; 96 | destVC.selectedAnimation = self.checkBox.onAnimationType; 97 | } else if ([segue.identifier isEqualToString:@"toCurrentSetup"]) { 98 | BEMCurrentSetupTableViewController *destVC = (BEMCurrentSetupTableViewController *)segue.destinationViewController; 99 | destVC.checkBox = self.checkBox; 100 | } 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 92 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 349 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 377 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 405 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 433 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 461 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 489 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 517 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 545 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 573 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 601 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 629 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "app-icon-setting@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "app-icon-setting@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "app-icon-spotlight@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "app-icon-spotlight@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "app-icon-iphone@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "app-icon-iphone@3x.png", 37 | "scale" : "3x" 38 | } 39 | ], 40 | "info" : { 41 | "version" : 1, 42 | "author" : "xcode" 43 | } 44 | } -------------------------------------------------------------------------------- /Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-iphone@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-iphone@2x.png -------------------------------------------------------------------------------- /Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-iphone@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-iphone@3x.png -------------------------------------------------------------------------------- /Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-setting@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-setting@2x.png -------------------------------------------------------------------------------- /Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-setting@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-setting@3x.png -------------------------------------------------------------------------------- /Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-spotlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-spotlight@2x.png -------------------------------------------------------------------------------- /Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-spotlight@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMCheckBox/a3292ebae9f0c2737b0c90281219dced2ce51ac8/Sample Project/CheckBox/Images.xcassets/AppIcon.appiconset/app-icon-spotlight@3x.png -------------------------------------------------------------------------------- /Sample Project/CheckBox/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Sample Project/CheckBox/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CheckBox 4 | // 5 | // Created by Bobo on 8/29/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sample Project/CheckBoxTests/AnimationManangerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationManangerTests.m 3 | // CheckBox 4 | // 5 | // Created by Bobo on 9/28/15. 6 | // Copyright © 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface AnimationManangerTests : XCTestCase 13 | 14 | @property (strong, nonatomic) BEMAnimationManager *manager; 15 | 16 | @end 17 | 18 | @implementation AnimationManangerTests 19 | 20 | - (void)setUp { 21 | [super setUp]; 22 | 23 | self.manager = [[BEMAnimationManager alloc] initWithAnimationDuration:10.0]; 24 | } 25 | 26 | - (void)testInit { 27 | XCTAssertNotNil(self.manager); 28 | XCTAssert(self.manager.animationDuration == 10.0); 29 | } 30 | 31 | - (void)testStrokeAnimation { 32 | CABasicAnimation * animation = [self.manager strokeAnimationReverse:NO]; 33 | XCTAssertNotNil(animation); 34 | XCTAssert(animation.duration == 10.0); 35 | XCTAssert([animation.fromValue isEqualToNumber:@0.0]); 36 | XCTAssert([animation.toValue isEqualToNumber:@1.0]); 37 | XCTAssert(animation.removedOnCompletion == NO); 38 | XCTAssert(animation.fillMode == kCAFillModeForwards); 39 | XCTAssert([animation.keyPath isEqualToString:@"strokeEnd"]); 40 | 41 | animation = [self.manager strokeAnimationReverse:YES]; 42 | XCTAssert([animation.fromValue isEqualToNumber:@1.0]); 43 | XCTAssert([animation.toValue isEqualToNumber:@0.0]); 44 | } 45 | 46 | - (void)tearDown { 47 | self.manager = nil; 48 | [super tearDown]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Sample Project/CheckBoxTests/CheckBoxTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CheckBoxTests.m 3 | // CheckBoxTests 4 | // 5 | // Created by Bobo on 8/29/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface CheckBoxTests : XCTestCase 14 | 15 | @property (strong, nonatomic) BEMCheckBox *checkBox; 16 | 17 | @end 18 | 19 | @implementation CheckBoxTests 20 | 21 | - (void)setUp { 22 | [super setUp]; 23 | 24 | self.checkBox = [BEMCheckBox new]; 25 | } 26 | 27 | - (void)tearDown { 28 | self.checkBox = nil; 29 | 30 | [super tearDown]; 31 | } 32 | 33 | - (void)testInit { 34 | 35 | XCTAssertNotNil(self.checkBox); 36 | 37 | // Default values 38 | XCTAssert(self.checkBox.on == NO, @"The default value for 'on' should be 'NO'"); 39 | XCTAssert(self.checkBox.hideBox == NO, @"The box shouldn't be hidden by default"); 40 | XCTAssert([self.checkBox.onTintColor isEqual:[UIColor colorWithRed:0 green:122.0/255.0 blue:255/255 alpha:1]], @"Default on tint color"); 41 | XCTAssert([self.checkBox.onFillColor isEqual:[UIColor clearColor]], @"Default on fill color"); 42 | XCTAssert([self.checkBox.onCheckColor isEqual:[UIColor colorWithRed:0 green:122.0/255.0 blue:255/255 alpha:1]], @"Default on check color"); 43 | XCTAssert([self.checkBox.tintColor isEqual:[UIColor lightGrayColor]], @"Default tint color"); 44 | XCTAssert(self.checkBox.lineWidth == 2.0, @"Default line width should be 2.0"); 45 | XCTAssert(self.checkBox.animationDuration == 0.5, @"Default animation duration should be 0.5"); 46 | XCTAssert(self.checkBox.onAnimationType == BEMAnimationTypeStroke, @"Default on animation should be of type stroke"); 47 | XCTAssert(self.checkBox.offAnimationType == BEMAnimationTypeStroke, @"Default off animation should be of type stroke"); 48 | XCTAssert([self.checkBox.backgroundColor isEqual:[UIColor clearColor]], @"Background color should be transparent"); 49 | } 50 | 51 | - (void)testSetOnAnimated { 52 | [self.checkBox setOn:YES animated:NO]; 53 | XCTAssertTrue(self.checkBox.on); 54 | [self.checkBox layoutIfNeeded]; 55 | XCTAssertEqual(self.checkBox.layer.sublayers.count, 3); 56 | 57 | [self.checkBox setOn:NO animated:NO]; 58 | XCTAssertFalse(self.checkBox.on); 59 | [self.checkBox layoutIfNeeded]; 60 | XCTAssertEqual(self.checkBox.layer.sublayers.count, 1); 61 | 62 | [self.checkBox setOn:YES animated:YES]; 63 | XCTAssertTrue(self.checkBox.on); 64 | XCTAssertEqual(self.checkBox.layer.sublayers.count, 3); 65 | 66 | [self.checkBox setOn:NO animated:YES]; 67 | XCTAssertFalse(self.checkBox.on); 68 | } 69 | 70 | - (void)testOn { 71 | self.checkBox.on = YES; 72 | XCTAssertTrue(self.checkBox.on); 73 | [self.checkBox layoutIfNeeded]; 74 | XCTAssertEqual(self.checkBox.layer.sublayers.count, 3); 75 | 76 | self.checkBox.on = NO; 77 | XCTAssertFalse(self.checkBox.on); 78 | [self.checkBox layoutIfNeeded]; 79 | XCTAssertEqual(self.checkBox.layer.sublayers.count, 1); 80 | } 81 | 82 | - (void)testReload { 83 | self.checkBox.on = NO; 84 | XCTAssertFalse(self.checkBox.on); 85 | 86 | [self.checkBox setNeedsDisplay]; 87 | XCTAssertFalse(self.checkBox.on); 88 | 89 | self.checkBox.on = YES; 90 | XCTAssertTrue(self.checkBox.on); 91 | 92 | [self.checkBox setNeedsDisplay]; 93 | XCTAssertTrue(self.checkBox.on); 94 | } 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /Sample Project/CheckBoxTests/GroupTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // GroupTests.m 3 | // CheckBox 4 | // 5 | // Created by Bobo on 10/18/16. 6 | // Copyright © 2016 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface GroupTests : XCTestCase 14 | 15 | @property (strong, nonatomic) NSArray *checkBoxes; 16 | 17 | @end 18 | 19 | @implementation GroupTests 20 | 21 | - (void)setUp { 22 | [super setUp]; 23 | 24 | NSMutableArray *checkBoxes = [NSMutableArray new]; 25 | 26 | for (NSInteger i = 0; i < 5; i++) { 27 | [checkBoxes addObject:[BEMCheckBox new]]; 28 | } 29 | self.checkBoxes = [NSArray arrayWithArray:checkBoxes]; 30 | } 31 | 32 | - (void)testSelectedCheckBox { 33 | BEMCheckBoxGroup *group = [[BEMCheckBoxGroup alloc] initWithCheckBoxes:self.checkBoxes]; 34 | XCTAssertNotNil(group); 35 | XCTAssertNil(group.selectedCheckBox); 36 | 37 | group.selectedCheckBox = [BEMCheckBox new]; 38 | XCTAssertNil(group.selectedCheckBox); 39 | XCTAssertEqual([self selectedCheckBoxForGroup:group], group.selectedCheckBox); 40 | XCTAssertEqual([self numberOfSelectedCheckBoxesForGroup:group], 0); 41 | 42 | group.selectedCheckBox = self.checkBoxes[1]; 43 | XCTAssertEqual(group.selectedCheckBox, self.checkBoxes[1]); 44 | XCTAssertEqual([self selectedCheckBoxForGroup:group], group.selectedCheckBox); 45 | XCTAssertEqual([self numberOfSelectedCheckBoxesForGroup:group], 1); 46 | 47 | group.selectedCheckBox = self.checkBoxes[2]; 48 | XCTAssertEqual(group.selectedCheckBox, self.checkBoxes[2]); 49 | XCTAssertEqual([self selectedCheckBoxForGroup:group], group.selectedCheckBox); 50 | XCTAssertEqual([self numberOfSelectedCheckBoxesForGroup:group], 1); 51 | 52 | group.selectedCheckBox = self.checkBoxes[0]; 53 | XCTAssertEqual(group.selectedCheckBox, self.checkBoxes[0]); 54 | XCTAssertEqual([self selectedCheckBoxForGroup:group], group.selectedCheckBox); 55 | XCTAssertEqual([self numberOfSelectedCheckBoxesForGroup:group], 1); 56 | 57 | group.selectedCheckBox = nil; 58 | XCTAssertNil(group.selectedCheckBox); 59 | XCTAssertEqual([self selectedCheckBoxForGroup:group], nil); 60 | XCTAssertEqual([self numberOfSelectedCheckBoxesForGroup:group], 0); 61 | } 62 | 63 | - (void)testAutoSelectFirstCheckBox { 64 | BEMCheckBoxGroup *group = [[BEMCheckBoxGroup alloc] initWithCheckBoxes:self.checkBoxes]; 65 | XCTAssertNotNil(group); 66 | XCTAssertNil(group.selectedCheckBox); 67 | 68 | group.mustHaveSelection = YES; 69 | XCTAssertNotNil(group.selectedCheckBox); 70 | 71 | group.selectedCheckBox = nil; 72 | XCTAssertNotNil(group.selectedCheckBox); 73 | } 74 | 75 | - (void)testAddCheckBox { 76 | BEMCheckBoxGroup *group = [[BEMCheckBoxGroup alloc] initWithCheckBoxes:self.checkBoxes]; 77 | XCTAssertNotNil(group); 78 | XCTAssertEqual(group.checkBoxes.count, self.checkBoxes.count); 79 | 80 | BEMCheckBox *checkBox = [BEMCheckBox new]; 81 | [group addCheckBoxToGroup:checkBox]; 82 | 83 | XCTAssertEqual(group.checkBoxes.count, self.checkBoxes.count + 1); 84 | } 85 | 86 | - (void)testRemoveCheckBox { 87 | BEMCheckBoxGroup *group = [[BEMCheckBoxGroup alloc] initWithCheckBoxes:self.checkBoxes]; 88 | XCTAssertNotNil(group); 89 | XCTAssertEqual(group.checkBoxes.count, self.checkBoxes.count); 90 | 91 | [group removeCheckBoxFromGroup:[self.checkBoxes firstObject]]; 92 | XCTAssertEqual(group.checkBoxes.count, self.checkBoxes.count - 1); 93 | } 94 | 95 | - (void)testEmptyGroup { 96 | BEMCheckBoxGroup *emptyGroup = [[BEMCheckBoxGroup alloc] initWithCheckBoxes: @[]]; 97 | XCTAssertNotNil(emptyGroup); 98 | XCTAssertEqual(emptyGroup.checkBoxes.count, 0); 99 | 100 | [emptyGroup removeCheckBoxFromGroup:[BEMCheckBox new]]; 101 | XCTAssertEqual(emptyGroup.checkBoxes.count, 0); 102 | 103 | emptyGroup.mustHaveSelection = YES; 104 | XCTAssertEqual(emptyGroup.checkBoxes.count, 0); 105 | 106 | [emptyGroup addCheckBoxToGroup:[BEMCheckBox new]]; 107 | XCTAssertEqual(emptyGroup.checkBoxes.count, 1); 108 | } 109 | 110 | #pragma mark Helper Methods 111 | 112 | - (NSInteger)numberOfSelectedCheckBoxesForGroup:(BEMCheckBoxGroup *)group { 113 | NSInteger numberOfSelectedCheckBoxes = 0; 114 | for (BEMCheckBox *checkBox in group.checkBoxes) { 115 | if (checkBox.on == YES) { 116 | numberOfSelectedCheckBoxes++; 117 | } 118 | } 119 | 120 | return numberOfSelectedCheckBoxes; 121 | } 122 | 123 | - (BEMCheckBox *)selectedCheckBoxForGroup:(BEMCheckBoxGroup *)group { 124 | for (BEMCheckBox *checkBox in group.checkBoxes) { 125 | if (checkBox.on == YES) { 126 | return checkBox; 127 | } 128 | } 129 | 130 | return nil; 131 | } 132 | 133 | - (void)tearDown { 134 | [super tearDown]; 135 | } 136 | 137 | @end 138 | -------------------------------------------------------------------------------- /Sample Project/CheckBoxTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sample Project/CheckBoxUITests/CheckBoxUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CheckBoxUITests.m 3 | // CheckBoxUITests 4 | // 5 | // Created by Boris Emorine on 9/2/16. 6 | // Copyright © 2016 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | @import BEMCheckBox; 11 | 12 | @interface CheckBoxUITests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation CheckBoxUITests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | 21 | self.continueAfterFailure = NO; 22 | [[[XCUIApplication alloc] init] launch]; 23 | } 24 | 25 | - (void)tearDown { 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testOn { 30 | XCUIElement *element = [[[[[[[[XCUIApplication alloc] init].otherElements containingType:XCUIElementTypeNavigationBar identifier:@"BEMCheckBox"] childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther] elementBoundByIndex:1]; 31 | XCTAssertTrue(element.isHittable); 32 | 33 | [element tap]; 34 | XCTAssertTrue(element.isHittable); 35 | 36 | [element tap]; 37 | XCTAssertTrue(element.isHittable); 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Sample Project/CheckBoxUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | --------------------------------------------------------------------------------