iOS 繪制一個表盤時鐘,秒針效果可以“掃秒/游走”
最近自己 也嘗試寫了一個表盤時鐘,初衷源于等車時候一個老奶奶問時間,我打開手機,時間數(shù)字對我來說相對敏感,但是老奶奶是看不清的,我想識別 還是看表盤 老遠(yuǎn) 看時針分針角度就可以識別當(dāng)前時間。
于是我想寫一個表盤時鐘。
效果圖:

基本原理,基本邏輯和其他時鐘大同小異:定時器 repeat 獲取當(dāng)前時分秒,計算旋轉(zhuǎn)角度,渲染UI。
幾個注意的關(guān)鍵點,重點,難點。
一.旋轉(zhuǎn)角度
以表盤為圓心,即 時針分針秒針繪制的矩形UI 錨點 anchorPoint. (默認(rèn)錨點 是矩形中心點 anchorPoint(0.5,0.5)))
//時鐘偏轉(zhuǎn)角度 CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0; //分鐘偏轉(zhuǎn)角度 CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0; //秒鐘旋轉(zhuǎn)角度 CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0; CGFloat prevSecAngle = ((components.second - 1) / 60.0) * M_PI * 2.0;
position 和 anchorPoint 關(guān)系:
(1)position是layer中的anchorPoint在superLayer中的位置坐標(biāo)。
(2)position與anchorPoint是處于不同坐標(biāo)空間中的重合點,修改重合點在一個坐標(biāo)空間的位置不影響該重合點在另一個坐標(biāo)空間中的位置
(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層的變化 一個不是,當(dāng)兩種秒針效果在真機中切換的時候 總會閃動 原因參見參考2
于是需要及時修改layer層的聯(lián)動變化添加了
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秒直接跳到下一個位置,但是在“掃描/游走秒針”效果下,仿佛臨界的跳動狀態(tài)不具有一致性,于是在“掃描/游走秒針”狀態(tài)下,時針 分針 添加一個1s de animation. 整體臨界效果就自然了
整體timer 定時任務(wù)如下:
#pragma mark -- 定時任務(wù) - (void)tick { // NSCalendarIdentifierGregorian : 指定日歷的算法 NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; // NSDateComponents封裝了日期的組件,年月日時分秒等(個人感覺像是平時用的model模型) // 調(diào)用NSCalendar的components:fromDate:方法返回一個NSDateComponents對象 // 需要的參數(shù)分別components:所需要的日期單位 date:目標(biāo)月份的date對象 // NSUInteger units = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;//所需要日期單位 NSDateComponents *components = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:[NSDate date]]; //時鐘偏轉(zhuǎn)角度 CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0; //分鐘偏轉(zhuǎn)角度 CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0; //秒鐘旋轉(zhuǎn)角度 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 關(guān)系)
2. https://blog.csdn.net/mydo/article/details/51553982
posted on 2019-01-21 16:56 ACM_Someone like you 閱讀(1032) 評論(0) 收藏 舉報
浙公網(wǎng)安備 33010602011771號