WorkTimer - Swift
随着工作压力的增大,工作和休息不能平衡,导致效率下降.这个小Demo模仿了Tomate的核心理念和动画.
在这个基础上优化了核心代码,减少了反复重绘图片和计算,降低了CPU的使用率,使得扩展性增加,更好的适配不同的机型不同的系统.
虽然界面设计的很简单,没有给设置时间等,但是最合理的模式其实还是默认模式,也就是25(工作)+5(休息)模式的反复进行,把效率提高到最大.
原项目:Tomate
本项目:WorkTimer
下面给出设计的布局
iPhone5下的布局:
模拟器下的布局:
其中最主要的还是对核心动画进行优化:
import UIKit import QuartzCore /** * Update Timer UI */ public protocol TimerViewProtocol { func updateTimer(durationInSeconds: CGFloat) } extension CGFloat { func numberTimerFormate() -> String { return String(format: "%02d", Int(self)) } } class TimerView: UIView, TimerViewProtocol { var totalTimeInSeconds: CGFloat { get{ return totalTime } set{ totalTime = newValue initTimerState() } } private var totalTime: CGFloat = 0.0 private var radius: CGFloat = 0.0 private var timerCenter: CGPoint = CGPoint(x: 0.0, y: 0.0) private let startAngle: CGFloat = -CGFloat(M_PI) / 2 private let endAngle: CGFloat = 3 * CGFloat(M_PI) / 2 private var minutesRingPath: UIBezierPath! private var secondsRingPath: UIBezierPath! private var fullRingPath: UIBezierPath! private var numberTimeLabel = UILabel() private let minutesShapeLayer: CAShapeLayer = CAShapeLayer() private let secondsShapeLayer: CAShapeLayer = CAShapeLayer() override init(frame: CGRect) { super.init(frame: frame) layer.addSublayer(minutesShapeLayer) layer.addSublayer(secondsShapeLayer) addSubview(numberTimeLabel) addConstraints(settingNumberTimeLabelConstraint()) backgroundColor = UIColor.clearColor() //backgroundColor = UIColor.redColor()/////////////////////////////////////////////////////////////////////////////////////////// print("init TimerView complete") } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. override func drawRect(rect: CGRect) { timerCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)) radius = rect.width / 2 - 10 settingMinuteStyle() settingSecondStyle() settingTimeLabelStyle() drawRing() initTimerState() print("Timer View drawRect:\(rect)-timerCenter:\(timerCenter)-radius:\(radius)") } func updateTimer(durationInSeconds: CGFloat) { minutesShapeLayer.strokeEnd = durationInSeconds / totalTime secondsShapeLayer.strokeEnd = durationInSeconds % 60 / 60 numberTimeLabel.text = (durationInSeconds / 60).numberTimerFormate() + ":" + (durationInSeconds % 60).numberTimerFormate() } private func initTimerState() { minutesShapeLayer.strokeEnd = 0.0 secondsShapeLayer.strokeEnd = 0.0 numberTimeLabel.text = CGFloat(0).numberTimerFormate() + ":" + CGFloat(0).numberTimerFormate() let dashLength = 2 * radius * CGFloat(M_PI) / (totalTime / 60.0); minutesShapeLayer.lineDashPattern = [dashLength - 2, 2] print("init Time State complete") } private func settingMinuteStyle() { minutesRingPath = UIBezierPath(arcCenter: timerCenter, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true) minutesShapeLayer.path = minutesRingPath.CGPath minutesShapeLayer.fillColor = UIColor.clearColor().CGColor minutesShapeLayer.strokeColor = TimerStyleKit.timerColor.CGColor minutesShapeLayer.lineWidth = 4.0 print("setting Minute Style") } private func settingSecondStyle() { secondsRingPath = UIBezierPath(arcCenter: timerCenter, radius: radius - 4, startAngle: startAngle, endAngle: endAngle, clockwise: true) secondsShapeLayer.path = secondsRingPath.CGPath secondsShapeLayer.fillColor = UIColor.clearColor().CGColor secondsShapeLayer.strokeColor = TimerStyleKit.timerColor.CGColor secondsShapeLayer.lineWidth = 1.0 print("setting Second Style") } private func settingTimeLabelStyle() { numberTimeLabel.textAlignment = .Center numberTimeLabel.textColor = TimerStyleKit.timerColor numberTimeLabel.font = UIFont(name: "HelveticaNeue-Thin", size: radius / 2 + 10) //numberTimeLabel.font = UIFont(name: "HelveticaNeue-Thin", size: 80) numberTimeLabel.adjustsFontSizeToFitWidth = true numberTimeLabel.center = timerCenter //numberTimeLabel.backgroundColor = UIColor.greenColor()/////////////////////////////////////////////////////////////////////////////////////////// print("setting TimeLabel Style") } private func drawRing() { TimerStyleKit.timerColor.set() fullRingPath = UIBezierPath(arcCenter: timerCenter, radius: radius + 4, startAngle: startAngle, endAngle: endAngle, clockwise: true) fullRingPath.lineWidth = 1.0 fullRingPath.stroke() } private func settingNumberTimeLabelConstraint() -> [NSLayoutConstraint] { numberTimeLabel.translatesAutoresizingMaskIntoConstraints = false var constraints = [NSLayoutConstraint]() if #available(iOS 9.0, *) { constraints.append(numberTimeLabel.centerXAnchor.constraintEqualToAnchor(centerXAnchor)) constraints.append(numberTimeLabel.centerYAnchor.constraintEqualToAnchor(centerYAnchor)) } else { // Fallback on earlier versions let views = ["numberTimeLabel": numberTimeLabel] constraints += NSLayoutConstraint.constraintsWithVisualFormat("H:|-40-[numberTimeLabel]-40-|", options: [], metrics: [:], views: views) //constraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|-40-[numberTimeLabel]-40-|", options: [], metrics: [:], views: views) } return constraints } }
原项目中反复重绘和计算固定不变的一些属性,导致cpu占有率还是挺高的.
由于项目经验不足,只能造轮子了.
经过这个小Demo的制作,也了解了很多UIView和代码约束布局的相关知识.
其实我们做东西不仅仅只追求好看,而是应该合理的优化.
合理的设计模式和代码优化,包括好的扩展性,才是我们应该追求的.