iOS 繪製一個錶盤時鐘,秒針效果能夠「掃秒/遊走」

最近本身 也嘗試寫了一個錶盤時鐘,初衷源於等車時候一個老奶奶問時間,我打開手機,時間數字對我來講相對敏感,可是老奶奶是看不清的,我想識別 仍是看錶盤 老遠 看時針分針角度就能夠識別當前時間。git

因而我想寫一個錶盤時鐘。github

     效果圖:算法

     

      基本原理,基本邏輯和其餘時鐘大同小異:定時器 repeat 獲取當前時分秒,計算旋轉角度,渲染UI。動畫

      幾個注意的關鍵點,重點,難點。spa

一.旋轉角度.net

    以錶盤爲圓心,即 時針分針秒針繪製的矩形UI 錨點 anchorPoint. (默認錨點 是矩形中心點 anchorPoint(0.5,0.5)))code

    //時鐘偏轉角度
    CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0;
    //分鐘偏轉角度
    CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0;
    //秒鐘旋轉角度
    CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0;
    CGFloat prevSecAngle = ((components.second - 1) / 60.0) * M_PI * 2.0;

    

 position 和 anchorPoint 關係:component

 (1)position是layer中的anchorPoint在superLayer中的位置座標。orm

 (2)position與anchorPoint是處於不一樣座標空間中的重合點,修改重合點在一個座標空間的位置不影響該重合點在另外一個座標空間中的位置對象

 (3)公式

    frame.origin.x = position.x - anchorPoint.x * bounds.size.width;
    frame.origin.y = position.y - anchorPoint.y * bounds.size.height;

二.秒針是否「掃秒或遊走秒針」

   每秒一動的秒針效果:

   起初使用了

   self.secondHandImageV.transform = CGAffineTransformMakeRotation(secsAngle);

  遊走秒針使用:

 

 //提早存儲秒針layer的初始位置
        [self.secondHandImageV.layer removeAnimationForKey:@"transform"];
        CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"transform"];
        ani.duration = 1.f;
         ani .removedOnCompletion= NO;
        //ani.delegate = self;
        ani.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(prevSecAngle , 0, 0, 1)];
      
        ani.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(secsAngle , 0, 0, 1)];
        [self.secondHandImageV.layer addAnimation:ani forKey:@"transform"];

   由於一個事layer層的變化 一個不是,當兩種秒針效果在真機中切換的時候 總會閃動 緣由參見參考2 

   因而須要及時修改layer層的聯動變化添加了

ani.delegate = self;

#pragma mark -CAAnimationDelegate - (void)animationDidStart:(CAAnimation *)anim
{
    //防止layer動畫閃動
    self.secondHandImageV.layer.transform = CATransform3DMakeRotation (self.secondAngel, 0, 0, 1);
    //NSLog(@"animationDidStart%@",self.secondHandImageV.layer.animationKeys);
    
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    //防止layer動畫閃動
    self.secondHandImageV.layer.transform = CATransform3DMakeRotation (self.secondAngel, 0, 0, 1);
    //NSLog(@"animationDidStop%@",self.secondHandImageV.layer.animationKeys);
}

三.時針分針動一下時候de效果

    期初都是知足條件 1秒直接跳到下一個位置,可是在「掃描/遊走秒針」效果下,彷彿臨界的跳動狀態不具備一致性,因而在「掃描/遊走秒針」狀態下,時針 分針 添加一個1s de animation.  總體臨界效果就天然了

總體timer 定時任務以下:

#pragma mark -- 定時任務 - (void)tick {
    // NSCalendarIdentifierGregorian : 指定日曆的算法
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    // NSDateComponents封裝了日期的組件,年月日時分秒等(我的感受像是平時用的model模型)
    // 調用NSCalendar的components:fromDate:方法返回一個NSDateComponents對象
    // 須要的參數分別components:所須要的日期單位 date:目標月份的date對象
    // NSUInteger units = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;//所須要日期單位
    NSDateComponents *components = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:[NSDate date]];
    //時鐘偏轉角度
    CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0;
    //分鐘偏轉角度
    CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0;
    //秒鐘旋轉角度
    CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0;
    CGFloat prevSecAngle = ((components.second - 1) / 60.0) * M_PI * 2.0;
    
    self.secondAngel = secsAngle ;
    
    if (self.isWanderSecond) {
        //提早存儲秒針layer的初始位置
        [self.secondHandImageV.layer removeAnimationForKey:@"transform"];
        CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"transform"];
        ani.duration = 1.f;
        ani .removedOnCompletion= NO;
        ani.delegate = self;
        ani.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(prevSecAngle , 0, 0, 1)];
      
        ani.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(secsAngle , 0, 0, 1)];
        [self.secondHandImageV.layer addAnimation:ani forKey:@"transform"];
    } else {
        [self.secondHandImageV.layer removeAnimationForKey:@"transform"];
        self.secondHandImageV.layer.transform = CATransform3DMakeRotation (secsAngle, 0, 0, 1);
        //self.secondHandImageV.transform = CGAffineTransformMakeRotation(secsAngle);
    }
    //
    if (self.isWanderSecond && self.isContinuous) {
        [UIView animateWithDuration:1.0 animations:^{
            self.hourHandImageV.transform = CGAffineTransformMakeRotation(hoursAngle);
            self.minuteHandImageV.transform = CGAffineTransformMakeRotation(minsAngle);
        }];
    } else {
        self.isContinuous = YES;
        self.hourHandImageV.transform = CGAffineTransformMakeRotation(hoursAngle);
        self.minuteHandImageV.transform = CGAffineTransformMakeRotation(minsAngle);
    }
}

 

github地址 TimeClock

 

參考

 

1.https://www.jianshu.com/p/2f8962055f21 (layer層 中 position 和 anchorPoint  關係)

2. https://blog.csdn.net/mydo/article/details/51553982

相關文章
相關標籤/搜索