From d5ef4e2bd40d9ac0c8e1ba391beb121f9e3e933c Mon Sep 17 00:00:00 2001 From: benoit-fueled Date: Tue, 25 Oct 2016 14:30:14 +0200 Subject: [PATCH 1/2] chore(3.0): update for Swift 3.0 support --- .travis.yml | 4 +- EZClockView.xcodeproj/project.pbxproj | 4 +- Sample.playground/section-1.swift | 8 +- Sample.playground/timeline.xctimeline | 2 +- Source/EZClockView.swift | 514 +++++++++++++------------- Source/MarkingsView.swift | 196 +++++----- 6 files changed, 364 insertions(+), 364 deletions(-) diff --git a/.travis.yml b/.travis.yml index 84e9185..951798b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode7.2 +osx_image: xcode8 xcode_workspace: EZClockView.xcworkspace xcode_scheme: EZClockView iOS -xcode_sdk: iphonesimulator9.2 +xcode_sdk: iphonesimulator10.0 diff --git a/EZClockView.xcodeproj/project.pbxproj b/EZClockView.xcodeproj/project.pbxproj index 93b508c..359bfbd 100644 --- a/EZClockView.xcodeproj/project.pbxproj +++ b/EZClockView.xcodeproj/project.pbxproj @@ -258,7 +258,7 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -277,7 +277,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.notbenoit.$(PRODUCT_NAME:rfc1034identifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Sample.playground/section-1.swift b/Sample.playground/section-1.swift index 3758467..c8b329e 100644 --- a/Sample.playground/section-1.swift +++ b/Sample.playground/section-1.swift @@ -21,7 +21,7 @@ import UIKit import EZClockView -let view = UIView(frame: CGRect(origin: CGPointZero, size: CGSizeMake(300.0, 200.0))) +let view = UIView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 300.0, height: 200.0))) let clock = EZClockView(frame: view.bounds) @@ -31,8 +31,8 @@ clock.minutes = 12 clock.seconds = 47 // You can also setup time like this -clock.setTime(NSDate(), animated: true) -clock.setTime(NSDate()) +clock.setTime(Date(), animated: true) +clock.setTime(Date()) // Customize face with border thickness and background color clock.faceBorderWidth = 3 @@ -53,7 +53,7 @@ clock.markingHourLength = 10 clock.markingMinuteLength = 5 clock.markingHourThickness = 3 -clock.markingMinuteColor = UIColor.darkGrayColor() +clock.markingMinuteColor = UIColor.darkGray view.addSubview(clock) diff --git a/Sample.playground/timeline.xctimeline b/Sample.playground/timeline.xctimeline index e975d85..bd342d6 100644 --- a/Sample.playground/timeline.xctimeline +++ b/Sample.playground/timeline.xctimeline @@ -3,7 +3,7 @@ version = "3.0"> diff --git a/Source/EZClockView.swift b/Source/EZClockView.swift index ddcd04b..84d9f79 100644 --- a/Source/EZClockView.swift +++ b/Source/EZClockView.swift @@ -21,260 +21,260 @@ import UIKit @IBDesignable -public class EZClockView: UIView { - - // MARK: - Properties - private var faceView: UIView = UIView() - private var centerView: UIView = UIView() - private var handHours: UIView = UIView() - private var handMinutes: UIView = UIView() - private var handSeconds: UIView = UIView() - private var markingsView: MarkingsView = MarkingsView(frame: CGRectZero) - - private var hourProperty: Int = 0 - private var minuteProperty: Int = 0 - private var secondProperty: Int = 0 - - // MARK: animation - /// Set the animation duration (the view is animated when calling the setTime methods) - public var animationDuration: NSTimeInterval = 0.3 - - // MARK: Time - /// Set this property to change the hour hand position. - @IBInspectable public var hours: Int { - get { - return hourProperty - } - set { - hourProperty = newValue - updateHands() - } - } - /// Set this property to change the minutes hand position. - @IBInspectable public var minutes: Int { - get { - return minuteProperty - } - set { - minuteProperty = newValue - updateHands() - } - } - /// Set this property to change the seconds hand position. - @IBInspectable public var seconds: Int { - get { - return secondProperty - } - set { - secondProperty = newValue - updateHands() - } - } - - // MARK: Face - /// Defines the background color of the face. Defaults to white. - @IBInspectable public var faceBackgroundColor: UIColor = UIColor.whiteColor() { didSet { faceView.backgroundColor = faceBackgroundColor } } - /// Defines the border color of the face. Defaults to black. - @IBInspectable public var faceBorderColor: UIColor = UIColor.blackColor() - /// Defines the border width of the face. Defaults to 2. - @IBInspectable public var faceBorderWidth: CGFloat = 2.0 - - // MARK: Center disc - /// Defines the color of the rounded part in the middle of the face, over the needles. Default is red. - @IBInspectable public var centerColor: UIColor = UIColor.redColor() { didSet { centerView.backgroundColor = centerColor } } - /// Desfines the width of the center circle. Default is 3.0. - @IBInspectable public var centerRadius: CGFloat = 3.0 { didSet { setupCenterView() } } - /// Defines the width for the border of this center part. Default is 1.0. - @IBInspectable public var centerBorderWidth: CGFloat = 1.0 { didSet { centerView.layer.borderWidth = centerBorderWidth } } - /// Defines the color for the border of this center part. Default is red. - @IBInspectable public var centerBorderColor: UIColor = UIColor.redColor() { didSet { centerView.layer.borderColor = centerBorderColor.CGColor } } - - // MARK: Hour hand - /// Defines the color for the hours hand. Default to black. - @IBInspectable public var hoursColor: UIColor = UIColor.blackColor() { didSet { handHours.backgroundColor = hoursColor } } - /// Defines the length of the hours hand. It is represented as a ratio of the radius of the face. Default to 0.5. - @IBInspectable public var hoursLength: CGFloat = 0.5 { - didSet { setupHand(handHours, lengthRatio: hoursLength, thickness: hoursThickness, offset: hoursOffset) } - } - /// Defines the thickness of the hours hand. Default is 4. - @IBInspectable public var hoursThickness: CGFloat = 4 { - didSet { setupHand(handHours, lengthRatio: hoursLength, thickness: hoursThickness, offset: hoursOffset) } - } - /// Defines the distance by which the hours hand will overlap over the center of the face. Default is 2. - @IBInspectable public var hoursOffset: CGFloat = 2 { - didSet { setupHand(handHours, lengthRatio: hoursLength, thickness: hoursThickness, offset: hoursOffset) } - } - - // MARK: Minute hand - /// Defines the color for the minutes hand. Default to black. - @IBInspectable public var minutesColor: UIColor = UIColor.blackColor() { didSet { handMinutes.backgroundColor = minutesColor } } - /// Defines the length of the minutes hand. It is represented as a ratio of the radius of the face. Default to 0.7. - @IBInspectable public var minutesLength: CGFloat = 0.7 { - didSet { setupHand(handMinutes, lengthRatio: minutesLength, thickness: minutesThickness, offset: minutesOffset) } - } - /// Defines the thickness of the minutes hand. Default is 2. - @IBInspectable public var minutesThickness: CGFloat = 2 { - didSet { setupHand(handMinutes, lengthRatio: minutesLength, thickness: minutesThickness, offset: minutesOffset) } - } - /// Defines the distance by which the minutes hand will overlap over the center of the face. Default is 2. - @IBInspectable public var minutesOffset: CGFloat = 2 { - didSet { setupHand(handMinutes, lengthRatio: minutesLength, thickness: minutesThickness, offset: minutesOffset) } - } - - // MARK: Second hand - /// Defines the color for the seconds hand. Default to red. - @IBInspectable public var secondsColor: UIColor = UIColor.redColor() { didSet { handSeconds.backgroundColor = secondsColor } } - /// Defines the length of the seconds hand. It is represented as a ratio of the radius of the face. Default to 0.8. - @IBInspectable public var secondsLength: CGFloat = 0.8 { - didSet { setupHand(handSeconds, lengthRatio: secondsLength, thickness: secondsThickness, offset: secondsOffset) } - } - /// Defines the thickness of the seconds hand. Default is 1. - @IBInspectable public var secondsThickness: CGFloat = 1 { - didSet { setupHand(handSeconds, lengthRatio: secondsLength, thickness: secondsThickness, offset: secondsOffset) } - } - /// Defines the distance by which the seconds hand will overlap over the center of the face. Default is 2. - @IBInspectable public var secondsOffset: CGFloat = 2 { - didSet { setupHand(handSeconds, lengthRatio: secondsLength, thickness: secondsThickness, offset: secondsOffset) } - } - - // MARK: Markings - // Margin from the border of the clock. - @IBInspectable public var markingBorderSpacing: CGFloat = 20 { didSet { markingsView.borderSpacing = markingBorderSpacing } } - - // Length in points of the hour markings. - @IBInspectable public var markingHourLength: CGFloat = 20 { didSet { markingsView.hourMarkingLength = markingHourLength } } - @IBInspectable public var markingHourThickness: CGFloat = 1 { didSet { markingsView.hourMarkingThickness = markingHourThickness } } - @IBInspectable public var markingHourColor: UIColor = UIColor.blackColor() { didSet { markingsView.hourMarkingColor = markingHourColor } } - - // Length in points of the minute markings. - @IBInspectable public var markingMinuteLength: CGFloat = 10 { didSet { markingsView.minuteMarkingLength = markingMinuteLength } } - @IBInspectable public var markingMinuteThickness: CGFloat = 1 { didSet { markingsView.minuteMarkingThickness = markingMinuteThickness } } - @IBInspectable public var markingMinuteColor: UIColor = UIColor.blackColor() { didSet { markingsView.minuteMarkingColor = markingMinuteColor } } - - @IBInspectable public var shouldDrawHourMarkings: Bool = true { didSet { markingsView.shouldDrawHourMarkings = shouldDrawHourMarkings } } - @IBInspectable public var shouldDrawMinuteMarkings: Bool = true { didSet { markingsView.shouldDrawMinuteMarkings = shouldDrawMinuteMarkings } } - - // MARK: - Public methods - /** - Set the time the clock will display. You can animate it or not. - - - parameter h: The hour to set - - parameter m: The minute to set - - parameter s: The second to set - - parameter animated: Whether or not the change should be animated (default to false). - */ - public func setTime(h h: Int, m: Int, s: Int, animated: Bool = false) { - hourProperty = h - minuteProperty = m - secondProperty = s - updateHands(animated) - } - - /** - Set the time the clock will display directly by using an NSDate instance. - - - parameter date: The date to display. Only hours, minutes, and seconds, will be taken into account. - - parameter animated: Whether or not the change should be animated (default to false). - */ - public func setTime(date: NSDate, animated: Bool = false) { - let components = NSCalendar.currentCalendar().components(([NSCalendarUnit.Hour, NSCalendarUnit.Minute, NSCalendarUnit.Second]), fromDate: date) - hourProperty = components.hour - minuteProperty = components.minute - secondProperty = components.second - updateHands(animated) - } - - public override func layoutSubviews() { - super.layoutSubviews() - - let clockRadius = min(self.bounds.size.width, self.bounds.size.height) - - // Reset all transforms - setupHand(handHours, lengthRatio: hoursLength, thickness: hoursThickness, offset: hoursOffset) - setupHand(handMinutes, lengthRatio: minutesLength, thickness: minutesThickness, offset: minutesOffset) - setupHand(handSeconds, lengthRatio: secondsLength, thickness: secondsThickness, offset: secondsOffset) - - setupCenterView() - - handHours.backgroundColor = hoursColor - handMinutes.backgroundColor = minutesColor - handSeconds.backgroundColor = secondsColor - - faceView.frame.size = CGSize(width: clockRadius, height: clockRadius) - faceView.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)) - faceView.layer.cornerRadius = clockRadius/2.0 - faceView.backgroundColor = faceBackgroundColor - faceView.layer.borderWidth = faceBorderWidth - faceView.layer.borderColor = faceBorderColor.CGColor - - markingsView.frame = faceView.frame - - setTime(h: hours, m: minutes, s: seconds) - } - - public override func willMoveToSuperview(newSuperview: UIView?) { - if (faceView.superview == nil) { - - self.backgroundColor = UIColor.clearColor() - - self.addSubview(faceView) - self.addSubview(handHours) - self.addSubview(handMinutes) - self.addSubview(handSeconds) - self.addSubview(centerView) - - self.addSubview(markingsView) - } - } - - // MARK: - Private methods - private func setupHand(hand: UIView, lengthRatio: CGFloat, thickness: CGFloat, offset: CGFloat) { - hand.transform = CGAffineTransformIdentity - hand.layer.allowsEdgeAntialiasing = true - - let clockRadius = min(self.bounds.size.width, self.bounds.size.height) - let handLength = (clockRadius/2.0) * CGFloat(lengthRatio) - - let anchorX: CGFloat = 0.5 - let anchorY: CGFloat = 1.0 - (offset/handLength) - hand.layer.anchorPoint = CGPoint(x: anchorX, y: anchorY) - - let centerInParent = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)) - hand.frame = CGRectMake(centerInParent.x-(thickness/2), centerInParent.y - handLength + offset, thickness, handLength) - - // Replace the hand at appropriate position - updateHands() - } - - private func setupCenterView() { - centerView.bounds = CGRect(origin: CGPointZero, size: CGSize(width: centerRadius*2, height: centerRadius*2)) - centerView.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)) - centerView.layer.cornerRadius = centerRadius - centerView.backgroundColor = centerColor - centerView.layer.borderColor = centerBorderColor.CGColor - centerView.layer.borderWidth = centerBorderWidth - } - - private func updateHands(animated: Bool = false) { - // Put everything in seconds to have ratios - let hoursInSeconds = (hours%12)*3600 - let minutesInSeconds = (minutes%60)*60 - let secondsInSeconds = (seconds%60) - - let hoursRatio = CGFloat(hoursInSeconds + minutesInSeconds + secondsInSeconds) / 43200.0 - let minutesRatio = CGFloat(minutesInSeconds + secondsInSeconds) / 3600.0 - let secondsRatio = CGFloat(secondsInSeconds) / 60.0 - - if (animated) { - UIView.animateWithDuration(animationDuration) { - self.handSeconds.transform = CGAffineTransformMakeRotation(CGFloat(2*M_PI)*secondsRatio) - self.handMinutes.transform = CGAffineTransformMakeRotation(CGFloat(2*M_PI)*minutesRatio) - self.handHours.transform = CGAffineTransformMakeRotation(CGFloat(2*M_PI)*hoursRatio) - } - } else { - handSeconds.transform = CGAffineTransformMakeRotation(CGFloat(2*M_PI)*secondsRatio) - handMinutes.transform = CGAffineTransformMakeRotation(CGFloat(2*M_PI)*minutesRatio) - handHours.transform = CGAffineTransformMakeRotation(CGFloat(2*M_PI)*hoursRatio) - } - } -} \ No newline at end of file +open class EZClockView: UIView { + + // MARK: - Properties + fileprivate var faceView: UIView = UIView() + fileprivate var centerView: UIView = UIView() + fileprivate var handHours: UIView = UIView() + fileprivate var handMinutes: UIView = UIView() + fileprivate var handSeconds: UIView = UIView() + fileprivate var markingsView: MarkingsView = MarkingsView(frame: CGRect.zero) + + fileprivate var hourProperty: Int = 0 + fileprivate var minuteProperty: Int = 0 + fileprivate var secondProperty: Int = 0 + + // MARK: animation + /// Set the animation duration (the view is animated when calling the setTime methods) + open var animationDuration: TimeInterval = 0.3 + + // MARK: Time + /// Set this property to change the hour hand position. + @IBInspectable open var hours: Int { + get { + return hourProperty + } + set { + hourProperty = newValue + updateHands() + } + } + /// Set this property to change the minutes hand position. + @IBInspectable open var minutes: Int { + get { + return minuteProperty + } + set { + minuteProperty = newValue + updateHands() + } + } + /// Set this property to change the seconds hand position. + @IBInspectable open var seconds: Int { + get { + return secondProperty + } + set { + secondProperty = newValue + updateHands() + } + } + + // MARK: Face + /// Defines the background color of the face. Defaults to white. + @IBInspectable open var faceBackgroundColor: UIColor = UIColor.white { didSet { faceView.backgroundColor = faceBackgroundColor } } + /// Defines the border color of the face. Defaults to black. + @IBInspectable open var faceBorderColor: UIColor = UIColor.black + /// Defines the border width of the face. Defaults to 2. + @IBInspectable open var faceBorderWidth: CGFloat = 2.0 + + // MARK: Center disc + /// Defines the color of the rounded part in the middle of the face, over the needles. Default is red. + @IBInspectable open var centerColor: UIColor = UIColor.red { didSet { centerView.backgroundColor = centerColor } } + /// Desfines the width of the center circle. Default is 3.0. + @IBInspectable open var centerRadius: CGFloat = 3.0 { didSet { setupCenterView() } } + /// Defines the width for the border of this center part. Default is 1.0. + @IBInspectable open var centerBorderWidth: CGFloat = 1.0 { didSet { centerView.layer.borderWidth = centerBorderWidth } } + /// Defines the color for the border of this center part. Default is red. + @IBInspectable open var centerBorderColor: UIColor = UIColor.red { didSet { centerView.layer.borderColor = centerBorderColor.cgColor } } + + // MARK: Hour hand + /// Defines the color for the hours hand. Default to black. + @IBInspectable open var hoursColor: UIColor = UIColor.black { didSet { handHours.backgroundColor = hoursColor } } + /// Defines the length of the hours hand. It is represented as a ratio of the radius of the face. Default to 0.5. + @IBInspectable open var hoursLength: CGFloat = 0.5 { + didSet { setupHand(handHours, lengthRatio: hoursLength, thickness: hoursThickness, offset: hoursOffset) } + } + /// Defines the thickness of the hours hand. Default is 4. + @IBInspectable open var hoursThickness: CGFloat = 4 { + didSet { setupHand(handHours, lengthRatio: hoursLength, thickness: hoursThickness, offset: hoursOffset) } + } + /// Defines the distance by which the hours hand will overlap over the center of the face. Default is 2. + @IBInspectable open var hoursOffset: CGFloat = 2 { + didSet { setupHand(handHours, lengthRatio: hoursLength, thickness: hoursThickness, offset: hoursOffset) } + } + + // MARK: Minute hand + /// Defines the color for the minutes hand. Default to black. + @IBInspectable open var minutesColor: UIColor = UIColor.black { didSet { handMinutes.backgroundColor = minutesColor } } + /// Defines the length of the minutes hand. It is represented as a ratio of the radius of the face. Default to 0.7. + @IBInspectable open var minutesLength: CGFloat = 0.7 { + didSet { setupHand(handMinutes, lengthRatio: minutesLength, thickness: minutesThickness, offset: minutesOffset) } + } + /// Defines the thickness of the minutes hand. Default is 2. + @IBInspectable open var minutesThickness: CGFloat = 2 { + didSet { setupHand(handMinutes, lengthRatio: minutesLength, thickness: minutesThickness, offset: minutesOffset) } + } + /// Defines the distance by which the minutes hand will overlap over the center of the face. Default is 2. + @IBInspectable open var minutesOffset: CGFloat = 2 { + didSet { setupHand(handMinutes, lengthRatio: minutesLength, thickness: minutesThickness, offset: minutesOffset) } + } + + // MARK: Second hand + /// Defines the color for the seconds hand. Default to red. + @IBInspectable open var secondsColor: UIColor = UIColor.red { didSet { handSeconds.backgroundColor = secondsColor } } + /// Defines the length of the seconds hand. It is represented as a ratio of the radius of the face. Default to 0.8. + @IBInspectable open var secondsLength: CGFloat = 0.8 { + didSet { setupHand(handSeconds, lengthRatio: secondsLength, thickness: secondsThickness, offset: secondsOffset) } + } + /// Defines the thickness of the seconds hand. Default is 1. + @IBInspectable open var secondsThickness: CGFloat = 1 { + didSet { setupHand(handSeconds, lengthRatio: secondsLength, thickness: secondsThickness, offset: secondsOffset) } + } + /// Defines the distance by which the seconds hand will overlap over the center of the face. Default is 2. + @IBInspectable open var secondsOffset: CGFloat = 2 { + didSet { setupHand(handSeconds, lengthRatio: secondsLength, thickness: secondsThickness, offset: secondsOffset) } + } + + // MARK: Markings + // Margin from the border of the clock. + @IBInspectable open var markingBorderSpacing: CGFloat = 20 { didSet { markingsView.borderSpacing = markingBorderSpacing } } + + // Length in points of the hour markings. + @IBInspectable open var markingHourLength: CGFloat = 20 { didSet { markingsView.hourMarkingLength = markingHourLength } } + @IBInspectable open var markingHourThickness: CGFloat = 1 { didSet { markingsView.hourMarkingThickness = markingHourThickness } } + @IBInspectable open var markingHourColor: UIColor = UIColor.black { didSet { markingsView.hourMarkingColor = markingHourColor } } + + // Length in points of the minute markings. + @IBInspectable open var markingMinuteLength: CGFloat = 10 { didSet { markingsView.minuteMarkingLength = markingMinuteLength } } + @IBInspectable open var markingMinuteThickness: CGFloat = 1 { didSet { markingsView.minuteMarkingThickness = markingMinuteThickness } } + @IBInspectable open var markingMinuteColor: UIColor = UIColor.black { didSet { markingsView.minuteMarkingColor = markingMinuteColor } } + + @IBInspectable open var shouldDrawHourMarkings: Bool = true { didSet { markingsView.shouldDrawHourMarkings = shouldDrawHourMarkings } } + @IBInspectable open var shouldDrawMinuteMarkings: Bool = true { didSet { markingsView.shouldDrawMinuteMarkings = shouldDrawMinuteMarkings } } + + // MARK: - Public methods + /** + Set the time the clock will display. You can animate it or not. + + - parameter h: The hour to set + - parameter m: The minute to set + - parameter s: The second to set + - parameter animated: Whether or not the change should be animated (default to false). + */ + open func setTime(h: Int, m: Int, s: Int, animated: Bool = false) { + hourProperty = h + minuteProperty = m + secondProperty = s + updateHands(animated) + } + + /** + Set the time the clock will display directly by using an NSDate instance. + + - parameter date: The date to display. Only hours, minutes, and seconds, will be taken into account. + - parameter animated: Whether or not the change should be animated (default to false). + */ + open func setTime(_ date: Date, animated: Bool = false) { + let components = (Calendar.current as NSCalendar).components(([NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]), from: date) + hourProperty = components.hour! + minuteProperty = components.minute! + secondProperty = components.second! + updateHands(animated) + } + + open override func layoutSubviews() { + super.layoutSubviews() + + let clockRadius = min(self.bounds.size.width, self.bounds.size.height) + + // Reset all transforms + setupHand(handHours, lengthRatio: hoursLength, thickness: hoursThickness, offset: hoursOffset) + setupHand(handMinutes, lengthRatio: minutesLength, thickness: minutesThickness, offset: minutesOffset) + setupHand(handSeconds, lengthRatio: secondsLength, thickness: secondsThickness, offset: secondsOffset) + + setupCenterView() + + handHours.backgroundColor = hoursColor + handMinutes.backgroundColor = minutesColor + handSeconds.backgroundColor = secondsColor + + faceView.frame.size = CGSize(width: clockRadius, height: clockRadius) + faceView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) + faceView.layer.cornerRadius = clockRadius/2.0 + faceView.backgroundColor = faceBackgroundColor + faceView.layer.borderWidth = faceBorderWidth + faceView.layer.borderColor = faceBorderColor.cgColor + + markingsView.frame = faceView.frame + + setTime(h: hours, m: minutes, s: seconds) + } + + open override func willMove(toSuperview newSuperview: UIView?) { + if (faceView.superview == nil) { + + self.backgroundColor = UIColor.clear + + self.addSubview(faceView) + self.addSubview(handHours) + self.addSubview(handMinutes) + self.addSubview(handSeconds) + self.addSubview(centerView) + + self.addSubview(markingsView) + } + } + + // MARK: - Private methods + fileprivate func setupHand(_ hand: UIView, lengthRatio: CGFloat, thickness: CGFloat, offset: CGFloat) { + hand.transform = CGAffineTransform.identity + hand.layer.allowsEdgeAntialiasing = true + + let clockRadius = min(self.bounds.size.width, self.bounds.size.height) + let handLength = (clockRadius/2.0) * CGFloat(lengthRatio) + + let anchorX: CGFloat = 0.5 + let anchorY: CGFloat = 1.0 - (offset/handLength) + hand.layer.anchorPoint = CGPoint(x: anchorX, y: anchorY) + + let centerInParent = CGPoint(x: self.bounds.midX, y: self.bounds.midY) + hand.frame = CGRect(x: centerInParent.x-(thickness/2), y: centerInParent.y - handLength + offset, width: thickness, height: handLength) + + // Replace the hand at appropriate position + updateHands() + } + + fileprivate func setupCenterView() { + centerView.bounds = CGRect(origin: CGPoint.zero, size: CGSize(width: centerRadius*2, height: centerRadius*2)) + centerView.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) + centerView.layer.cornerRadius = centerRadius + centerView.backgroundColor = centerColor + centerView.layer.borderColor = centerBorderColor.cgColor + centerView.layer.borderWidth = centerBorderWidth + } + + fileprivate func updateHands(_ animated: Bool = false) { + // Put everything in seconds to have ratios + let hoursInSeconds = (hours%12)*3600 + let minutesInSeconds = (minutes%60)*60 + let secondsInSeconds = (seconds%60) + + let hoursRatio = CGFloat(hoursInSeconds + minutesInSeconds + secondsInSeconds) / 43200.0 + let minutesRatio = CGFloat(minutesInSeconds + secondsInSeconds) / 3600.0 + let secondsRatio = CGFloat(secondsInSeconds) / 60.0 + + if (animated) { + UIView.animate(withDuration: animationDuration, animations: { + self.handSeconds.transform = CGAffineTransform(rotationAngle: CGFloat(2*M_PI)*secondsRatio) + self.handMinutes.transform = CGAffineTransform(rotationAngle: CGFloat(2*M_PI)*minutesRatio) + self.handHours.transform = CGAffineTransform(rotationAngle: CGFloat(2*M_PI)*hoursRatio) + }) + } else { + handSeconds.transform = CGAffineTransform(rotationAngle: CGFloat(2*M_PI)*secondsRatio) + handMinutes.transform = CGAffineTransform(rotationAngle: CGFloat(2*M_PI)*minutesRatio) + handHours.transform = CGAffineTransform(rotationAngle: CGFloat(2*M_PI)*hoursRatio) + } + } +} diff --git a/Source/MarkingsView.swift b/Source/MarkingsView.swift index 3e36a71..8f8a268 100644 --- a/Source/MarkingsView.swift +++ b/Source/MarkingsView.swift @@ -21,102 +21,102 @@ import UIKit internal class MarkingsView: UIView { - - // Margin from the border of the clock. - internal var borderSpacing: CGFloat = 20 { didSet { setNeedsDisplay() } } - - // Length in points of the hour markings. - internal var hourMarkingLength: CGFloat = 20 { didSet { setNeedsDisplay() } } - internal var hourMarkingThickness: CGFloat = 1 { didSet { setNeedsDisplay() } } - internal var hourMarkingColor: UIColor = UIColor.blackColor() { didSet { setNeedsDisplay() } } - - // Length in points of the minute markings. - internal var minuteMarkingLength: CGFloat = 10 { didSet { setNeedsDisplay() } } - internal var minuteMarkingThickness: CGFloat = 1 { didSet { setNeedsDisplay() } } - internal var minuteMarkingColor: UIColor = UIColor.blackColor() { didSet { setNeedsDisplay() } } - - internal var shouldDrawHourMarkings: Bool = true { didSet { setNeedsDisplay() } } - internal var shouldDrawMinuteMarkings: Bool = true { didSet { setNeedsDisplay() } } - - override init(frame: CGRect) { - super.init(frame: frame) - self.backgroundColor = UIColor.clearColor() - } - - required internal init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - self.backgroundColor = UIColor.clearColor() - } - - override internal func drawRect(rect: CGRect) { - let context = UIGraphicsGetCurrentContext() - CGContextClearRect(context!, rect) - CGContextSetAllowsAntialiasing(context!, true) - CGContextSetShouldAntialias(context!, true) - CGContextSaveGState(context!) - - // Get the size of the clock (a square at the center of the rect) - let size = min(rect.size.width, rect.size.height) - let lineLength = size/2 - borderSpacing - let center = CGPoint(x: CGRectGetMidX(rect), y: CGRectGetMidY(rect)) - - // Draw 12 hour marks - let hourOffsetAngle: CGFloat = CGFloat(M_PI/6.0) - let hourPath = CGPathCreateMutable() - CGPathMoveToPoint(hourPath, nil, center.x, center.y) - for i in 0..<12 { - let x = center.x + lineLength * sin(CGFloat(i) * hourOffsetAngle) - let y = center.y - lineLength * cos(CGFloat(i) * hourOffsetAngle) - CGPathAddLineToPoint(hourPath, nil, x, y) - CGPathMoveToPoint(hourPath, nil, center.x, center.y) - } - - // Clip for hours - let hoursMaskRadius = lineLength - hourMarkingLength - CGContextBeginPath(context!) - CGContextAddRect(context!, CGContextGetClipBoundingBox(context!)) - CGContextAddEllipseInRect(context!, CGRect(origin: CGPoint(x: center.x - hoursMaskRadius, y: center.y - hoursMaskRadius), size: CGSize(width: hoursMaskRadius*2, height: hoursMaskRadius*2))) - CGContextEOClip(context!) - - // Draw hour markings - if shouldDrawHourMarkings { - hourMarkingColor.set() - CGContextSetLineWidth(context!, hourMarkingThickness) - CGContextAddPath(context!, hourPath) - CGContextStrokePath(context!) - } - CGContextRestoreGState(context!) - - CGContextSaveGState(context!) - - let minuteOffsetAngle: CGFloat = CGFloat(M_PI/30.0) - let minutePath = CGPathCreateMutable() - CGPathMoveToPoint(minutePath, nil, center.x, center.y) - for i in 0...61 { - if (i % 5 != 0) { // Minutes markings do not overlap hours markings - let x = center.x + lineLength * sin(CGFloat(i) * minuteOffsetAngle) - let y = center.y - lineLength * cos(CGFloat(i) * minuteOffsetAngle) - CGPathAddLineToPoint(minutePath, nil, x, y) - CGPathMoveToPoint(minutePath, nil, center.x, center.y) - } - } - - // Clip for minutes - let minutesMaskRadius = lineLength - minuteMarkingLength - CGContextBeginPath(context!) - CGContextAddRect(context!, CGContextGetClipBoundingBox(context!)) - CGContextAddEllipseInRect(context!, CGRect(origin: CGPoint(x: center.x - minutesMaskRadius, y: center.y - minutesMaskRadius), size: CGSize(width: minutesMaskRadius*2, height: minutesMaskRadius*2))) - CGContextEOClip(context!) - - // Draw minute markings - if shouldDrawMinuteMarkings { - minuteMarkingColor.set() - CGContextSetLineWidth(context!, minuteMarkingThickness) - CGContextAddPath(context!, minutePath) - CGContextStrokePath(context!) - } - CGContextRestoreGState(context!) - // --------------- - } - + + // Margin from the border of the clock. + internal var borderSpacing: CGFloat = 20 { didSet { setNeedsDisplay() } } + + // Length in points of the hour markings. + internal var hourMarkingLength: CGFloat = 20 { didSet { setNeedsDisplay() } } + internal var hourMarkingThickness: CGFloat = 1 { didSet { setNeedsDisplay() } } + internal var hourMarkingColor: UIColor = UIColor.black { didSet { setNeedsDisplay() } } + + // Length in points of the minute markings. + internal var minuteMarkingLength: CGFloat = 10 { didSet { setNeedsDisplay() } } + internal var minuteMarkingThickness: CGFloat = 1 { didSet { setNeedsDisplay() } } + internal var minuteMarkingColor: UIColor = UIColor.black { didSet { setNeedsDisplay() } } + + internal var shouldDrawHourMarkings: Bool = true { didSet { setNeedsDisplay() } } + internal var shouldDrawMinuteMarkings: Bool = true { didSet { setNeedsDisplay() } } + + override init(frame: CGRect) { + super.init(frame: frame) + self.backgroundColor = UIColor.clear + } + + required internal init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.backgroundColor = UIColor.clear + } + + override internal func draw(_ rect: CGRect) { + guard let context = UIGraphicsGetCurrentContext() else { return } + context.clear(rect) + context.setAllowsAntialiasing(true) + context.setShouldAntialias(true) + context.saveGState() + + // Get the size of the clock (a square at the center of the rect) + let size = min(rect.size.width, rect.size.height) + let lineLength = size/2 - borderSpacing + let center = CGPoint(x: rect.midX, y: rect.midY) + + // Draw 12 hour marks + let hourOffsetAngle: CGFloat = CGFloat(M_PI/6.0) + let hourPath = CGMutablePath() + hourPath.move(to: center) + for i in 0..<12 { + let x = center.x + lineLength * sin(CGFloat(i) * hourOffsetAngle) + let y = center.y - lineLength * cos(CGFloat(i) * hourOffsetAngle) + hourPath.addLine(to: CGPoint(x: x,y: y)) + hourPath.move(to: center) + } + + // Clip for hours + let hoursMaskRadius = lineLength - hourMarkingLength + context.beginPath() + context.addRect(context.boundingBoxOfClipPath) + context.addEllipse(in: CGRect(origin: CGPoint(x: center.x - hoursMaskRadius, y: center.y - hoursMaskRadius), size: CGSize(width: hoursMaskRadius*2, height: hoursMaskRadius*2))) + context.clip(using: CGPathFillRule.evenOdd) + + // Draw hour markings + if shouldDrawHourMarkings { + hourMarkingColor.set() + context.setLineWidth(hourMarkingThickness) + context.addPath(hourPath) + context.strokePath() + } + context.restoreGState() + + context.saveGState() + + let minuteOffsetAngle: CGFloat = CGFloat(M_PI/30.0) + let minutePath = CGMutablePath() + minutePath.move(to: center) + for i in 0...61 { + if (i % 5 != 0) { // Minutes markings do not overlap hours markings + let x = center.x + lineLength * sin(CGFloat(i) * minuteOffsetAngle) + let y = center.y - lineLength * cos(CGFloat(i) * minuteOffsetAngle) + minutePath.addLine(to: CGPoint(x: x, y: y)) + minutePath.move(to: center) + } + } + + // Clip for minutes + let minutesMaskRadius = lineLength - minuteMarkingLength + context.beginPath() + context.addRect(context.boundingBoxOfClipPath) + context.addEllipse(in: CGRect(origin: CGPoint(x: center.x - minutesMaskRadius, y: center.y - minutesMaskRadius), size: CGSize(width: minutesMaskRadius*2, height: minutesMaskRadius*2))) + context.clip(using: CGPathFillRule.evenOdd) + + // Draw minute markings + if shouldDrawMinuteMarkings { + minuteMarkingColor.set() + context.setLineWidth(minuteMarkingThickness) + context.addPath(minutePath) + context.strokePath() + } + context.restoreGState() + // --------------- + } + } From a3c58538654dd8d834db5d44c4736f1de15d0d71 Mon Sep 17 00:00:00 2001 From: benoit-fueled Date: Tue, 25 Oct 2016 14:31:49 +0200 Subject: [PATCH 2/2] chore(3.0): bump version to 3.0 --- .travis.yml | 5 +++++ EZClockView.podspec | 2 +- Source/Info.plist | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 951798b..59f9154 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,8 @@ osx_image: xcode8 xcode_workspace: EZClockView.xcworkspace xcode_scheme: EZClockView iOS xcode_sdk: iphonesimulator10.0 +env: + global: + - IOS_SDK=iphonesimulator10.0 +script: + - xcodebuild -workspace EZClockView.xcworkspace -scheme EZClockView\ iOS -sdk $IOS_SDK build analyze diff --git a/EZClockView.podspec b/EZClockView.podspec index fcdc32c..2729ebe 100644 --- a/EZClockView.podspec +++ b/EZClockView.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'EZClockView' - s.version = '1.1.2' + s.version = '1.2' s.license = 'MIT' s.summary = 'iOS framework to display and customize a clock.' s.homepage = 'https://github.com/notbenoit/EZClockView' diff --git a/Source/Info.plist b/Source/Info.plist index 0c61092..602d864 100644 --- a/Source/Info.plist +++ b/Source/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.1.3 + 1.2 CFBundleSignature ???? CFBundleVersion