News Digest(雅虎新聞)模仿秀第四彈

最近得空做了一個(gè)小的新聞?lì)怉PP,基本上都是照著News Digest的模子刻出來的,之所以這個(gè)為參考,是因?yàn)橛X得News Digest這個(gè)APP做得真的很酷炫!


猛戳這里獲取整個(gè)項(xiàng)目源代碼
項(xiàng)目前端主要由swift編寫,本地?cái)?shù)據(jù)用CoreData,后端由Node.js編寫,后臺(tái)數(shù)據(jù)庫用MongoDB。

News Digest(雅虎新聞)模仿秀第一彈
News Digest(雅虎新聞)模仿秀第二彈
News Digest(雅虎新聞)模仿秀第三彈

這期我們來說一下倒計(jì)時(shí)動(dòng)畫的實(shí)現(xiàn),先上效果圖:


倒計(jì)時(shí)效果圖

這里要分兩部分來講,一部分是圓圈動(dòng)畫的填充,一部分是時(shí)間的快速滾動(dòng),位于項(xiàng)目CustomView/MenuView和CustomView/CountdownView

  1. 圓圈動(dòng)畫的執(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,就是動(dòng)圖底層那一個(gè)灰色的圈,我們?cè)O(shè)置strokeEnd = 1.0(就是說完全填充,形成一個(gè)閉環(huán)),這個(gè)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方法是設(shè)置圓圈的frame,讓它形成位于圓心的,半徑為defaultCircleRadius的圓,然后用UIBezierPath繪制路徑,每次調(diào)用layoutSubviews方法把路徑賦值給circleLayer
layoutSubviews調(diào)用時(shí)機(jī):

  - 直接調(diào)用setLayoutSubviews。
  - addSubview的時(shí)候。
  - 當(dāng)view的frame發(fā)生改變的時(shí)候。
  - 滑動(dòng)UIScrollView的時(shí)候。
  - 旋轉(zhuǎn)Screen會(huì)觸發(fā)父UIView上的layoutSubviews事件。
  - 改變一個(gè)UIView大小的時(shí)候也會(huì)觸發(fā)父UIView上的layoutSubviews事件。

期初我打算用UIView.animateWithDuration來賦值circleLayer的strokeEnd參數(shù),然后發(fā)現(xiàn)無論我設(shè)置duration是多少,動(dòng)畫執(zhí)行時(shí)間都是一樣的,后來查了一下資料才發(fā)現(xiàn)UIView.animateWithDuration只能動(dòng)畫改變這幾個(gè)參數(shù)

        /*
         *   UIView.animateWithDuration(13.2, animations: {
         *       self.circleLayer.strokeEnd = CGFloat(interval/43200)
         *   })
         *   這里執(zhí)行方式不可以使用UIView.animateWithDuration,只能用CAAnimations
         *   UIView動(dòng)畫執(zhí)行只能改變一下幾個(gè)參數(shù)
         *
         *   The following properties of the UIView class are animatable:
         *   @property frame
         *   @property bounds
         *   @property center
         *   @property transform
         *   @property alpha
         *   @property backgroundColor
         *   @property contentStretch
         */

所以動(dòng)畫執(zhí)行strokeEnd的改變只能使用CAAnimations,只需要把strokeEnd的數(shù)值賦值給toValue,然后設(shè)置執(zhí)行時(shí)間即可

    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; // 保留動(dòng)畫后的樣子
        // 設(shè)置Delegate
        animation.delegate = self
        return animation
    }
  1. 時(shí)間的快速滾動(dòng)效果
    其實(shí)中間就是一個(gè)UILabel,然后動(dòng)態(tài)修改它的attributedText即可
    這個(gè)數(shù)字快速滾動(dòng)效果,我是模仿下面這位大大的代碼寫的
    滾動(dòng)的數(shù)字:FlickerNumber
    如果需要詳細(xì)了解,戳上面這個(gè)鏈接就可以詳細(xì)了解.
    總的來說,大概實(shí)現(xiàn)思路就是:
  • 設(shè)定起始數(shù)字/終止數(shù)字/執(zhí)行時(shí)間等
  • 設(shè)定數(shù)字滾動(dòng)的頻率,比如說1/30等等
  • 然后根據(jù)終止數(shù)字*頻率/執(zhí)行時(shí)間,就獲得每次數(shù)字變化的值
  • 最后一個(gè)NSTimer以頻率來執(zhí)行改變UILabel的值
  1. 滾動(dòng)圈圈下面那個(gè)日期選擇
    具體就不細(xì)說了,就一個(gè)UICollectionView

今天就到這里了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容