最近得空做了一個小的新聞類APP查牌,基本上都是照著News Digest的模子刻出來的事期,之所以這個為參考,是因為覺得News Digest這個APP做得真的很酷炫纸颜!
猛戳這里獲取整個項目源代碼
項目前端主要由swift編寫兽泣,本地數(shù)據(jù)用CoreData,后端由Node.js編寫胁孙,后臺數(shù)據(jù)庫用MongoDB唠倦。
News Digest(雅虎新聞)模仿秀第一彈
News Digest(雅虎新聞)模仿秀第二彈
News Digest(雅虎新聞)模仿秀第三彈
這期我們來說一下倒計時動畫的實現(xiàn),先上效果圖:
這里要分兩部分來講涮较,一部分是圓圈動畫的填充稠鼻,一部分是時間的快速滾動,位于項目CustomView/MenuView和CustomView/CountdownView
- 圓圈動畫的執(zhí)行
init(timeType: TimeType) {
super.init(frame: defaultFrame)
type = timeType
self.backgroundColor = UIColor.clearColor()
// CAShaperLayer Setting
circleShadowLayer.frame = self.bounds
circleShadowLayer.fillColor = UIColor.clearColor().CGColor
circleShadowLayer.lineWidth = 2.0
circleShadowLayer.strokeEnd = 1.0
circleShadowLayer.strokeColor = UIColor.RGBColor(255, green: 255, blue: 255, alpha: 0.2).CGColor
circleLayer.frame = self.bounds
circleLayer.fillColor = UIColor.clearColor().CGColor
circleLayer.lineWidth = 2.0
circleLayer.strokeEnd = 0
circleLayer.strokeColor = UIColor.RGBColor(0, green: 121, blue: 166, alpha: 1).CGColor
self.layer.addSublayer(circleShadowLayer)
self.layer.addSublayer(circleLayer)
}
這里的circleShadowLayer狂票,就是動圖底層那一個灰色的圈候齿,我們設置strokeEnd = 1.0(就是說完全填充,形成一個閉環(huán))闺属,這個strokeEnd是從0.0-1.0范圍
override func layoutSubviews() {
super.layoutSubviews()
defaultCircleRadius = (WIDTH - 100) < (self.bounds.height - 32) ? (WIDTH - 100)/2.0 : defaultCircleRadius
circleShadowLayer.frame = self.bounds
circleShadowLayer.path = circlePath().CGPath
circleLayer.frame = self.bounds
circleLayer.path = circlePath().CGPath
}
//MARK: - CirclePath
func circlePath() -> UIBezierPath {
return UIBezierPath.init(ovalInRect: circleFrame())
}
func circleFrame() -> CGRect {
var circleFrame = CGRect(x: 0, y: 0, width: 2*defaultCircleRadius, height: 2*defaultCircleRadius)
circleFrame.origin.x = CGRectGetMidX(circleShadowLayer.bounds) - CGRectGetMidX(circleFrame)
circleFrame.origin.y = CGRectGetMidY(circleShadowLayer.bounds) - CGRectGetMidY(circleFrame)
return circleFrame
}
circleFrame方法是設置圓圈的frame慌盯,讓它形成位于圓心的,半徑為defaultCircleRadius的圓掂器,然后用UIBezierPath繪制路徑亚皂,每次調用layoutSubviews方法把路徑賦值給circleLayer
layoutSubviews調用時機:
- 直接調用setLayoutSubviews。
- addSubview的時候国瓮。
- 當view的frame發(fā)生改變的時候灭必。
- 滑動UIScrollView的時候。
- 旋轉Screen會觸發(fā)父UIView上的layoutSubviews事件巍膘。
- 改變一個UIView大小的時候也會觸發(fā)父UIView上的layoutSubviews事件厂财。
期初我打算用UIView.animateWithDuration來賦值circleLayer的strokeEnd參數(shù),然后發(fā)現(xiàn)無論我設置duration是多少峡懈,動畫執(zhí)行時間都是一樣的璃饱,后來查了一下資料才發(fā)現(xiàn)UIView.animateWithDuration只能動畫改變這幾個參數(shù)
/*
* UIView.animateWithDuration(13.2, animations: {
* self.circleLayer.strokeEnd = CGFloat(interval/43200)
* })
* 這里執(zhí)行方式不可以使用UIView.animateWithDuration,只能用CAAnimations
* UIView動畫執(zhí)行只能改變一下幾個參數(shù)
*
* The following properties of the UIView class are animatable:
* @property frame
* @property bounds
* @property center
* @property transform
* @property alpha
* @property backgroundColor
* @property contentStretch
*/
所以動畫執(zhí)行strokeEnd的改變只能使用CAAnimations肪康,只需要把strokeEnd的數(shù)值賦值給toValue荚恶,然后設置執(zhí)行時間即可
func animationExecute() {
circleLayer.addAnimation(self.circleAnimationImplement(1.6, delay: 0.3, toValue: interval!/43200.0), forKey: nil)
}
// Animation Implement
private func circleAnimationImplement(duration: NSTimeInterval, delay: Double, toValue: Double) -> CABasicAnimation {
let animation = CABasicAnimation.init(keyPath: "strokeEnd")
animation.duration = duration < 0.8 ? 0.8 : duration
animation.beginTime = CACurrentMediaTime() + delay
animation.fromValue = 0.0
animation.toValue = toValue
animation.removedOnCompletion = false // 這里如果不是false fillMode屬性不起作用
animation.fillMode = kCAFillModeForwards; // 保留動畫后的樣子
// 設置Delegate
animation.delegate = self
return animation
}
- 時間的快速滾動效果
其實中間就是一個UILabel,然后動態(tài)修改它的attributedText即可
這個數(shù)字快速滾動效果磷支,我是模仿下面這位大大的代碼寫的
滾動的數(shù)字:FlickerNumber
如果需要詳細了解谒撼,戳上面這個鏈接就可以詳細了解.
總的來說,大概實現(xiàn)思路就是:
- 設定起始數(shù)字/終止數(shù)字/執(zhí)行時間等
- 設定數(shù)字滾動的頻率雾狈,比如說1/30等等
- 然后根據(jù)終止數(shù)字*頻率/執(zhí)行時間廓潜,就獲得每次數(shù)字變化的值
- 最后一個NSTimer以頻率來執(zhí)行改變UILabel的值
- 滾動圈圈下面那個日期選擇
具體就不細說了,就一個UICollectionView
今天就到這里了。