您的位置:首页 - 教程 - IOS - 正文
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和代码约束布局的相关知识.

其实我们做东西不仅仅只追求好看,而是应该合理的优化.

合理的设计模式和代码优化,包括好的扩展性,才是我们应该追求的.


评论: