司機(jī)王教你用CALayer寫(xiě)一個(gè)iOS時(shí)鐘效果

純屬原創(chuàng),轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝

首先我們先看一下需求

按照MAC的系統(tǒng)時(shí)鐘仿照寫(xiě)一個(gè)類(lèi)似的時(shí)鐘效果


然后我們著手分析一個(gè)這個(gè)如何實(shí)現(xiàn)

首先這個(gè)不需要和用戶(hù)有任何交互,所以我們推薦使用CALayer隱式動(dòng)畫(huà)去完成

然后我們讓設(shè)計(jì)人員先畫(huà)出一個(gè)表盤(pán)給我們,設(shè)置他的長(zhǎng)寬都為200

其次,我們就要通過(guò)需求來(lái)描述CALayer的anchorPoint與position點(diǎn)在哪里

至于這兩個(gè)點(diǎn)是什么(也就是“錨點(diǎn)”),徹底理解position與anchorPoint - yongyinmg的專(zhuān)欄 - 博客頻道 - CSDN.NET,這篇文章說(shuō)的很清楚了,這里就不跟大家解釋

我們可以看到,所有的layer都是基于錨點(diǎn)去旋轉(zhuǎn)的,也就是表盤(pán)的中心點(diǎn),那么position屬性也就是表盤(pán)的長(zhǎng)寬的一半,由于anchorPoint的X,Y屬性取值范圍是0-1之間,以秒針舉例,如果我們想讓秒針站立在表盤(pán)中上,那么秒針的X即為0.5,Y為1

在設(shè)置下秒針的bound,寬度為1,長(zhǎng)度為表盤(pán)的半徑-20

這樣我們可以輕松的將秒針針添加到表盤(pán)上

    CALayer * secondL = [CALayer layer];
    
    secondL.backgroundColor = [UIColor redColor].CGColor ;

    // 設(shè)置錨點(diǎn)
    
    secondL.anchorPoint = CGPointMake(0.5, 1);
    
    secondL.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    secondL.bounds = CGRectMake(0, 0, 1, kClockW * 0.5 - 20);
    

    [_clockView.layer addSublayer:secondL];

    _secondLayer = secondL;

同理,時(shí)針和分針也是一樣,只不過(guò)長(zhǎng)度和顏色,圓角不一樣

   CALayer * layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor blackColor].CGColor ;
    
    // 設(shè)置錨點(diǎn)
    
    layer.anchorPoint = CGPointMake(0.5, 1);
    
    layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 20);
    
    layer.cornerRadius = 4;
    
    [_clockView.layer addSublayer:layer];
    
    _mintueLayer = layer;

     CALayer * layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor blackColor].CGColor ;
    
    // 設(shè)置錨點(diǎn)
    
    layer.anchorPoint = CGPointMake(0.5, 1);
    
    layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 40);
    
    layer.cornerRadius = 4;
    
    [_clockView.layer addSublayer:layer];
    
    _hourLayer = layer;

這里一定要注意的是添加順序,一般來(lái)講秒針在最上層,所以秒針的layer是最后添加的

現(xiàn)在UI層我們已經(jīng)添加好了,接下來(lái)就該考慮如何讓時(shí)鐘動(dòng)起來(lái)了

讓時(shí)鐘動(dòng)起來(lái),我們先要知道時(shí)分秒他們?cè)诒肀P(pán)上所謂轉(zhuǎn)動(dòng)的角度

通過(guò)小學(xué)運(yùn)算可以得知,秒針在一秒鐘內(nèi)在表盤(pán)里轉(zhuǎn)動(dòng)的度數(shù)是6度(一個(gè)圓形是360度,360除以60),拿現(xiàn)在的系統(tǒng)的秒數(shù)*6就是現(xiàn)在秒針的具體度數(shù)

分針在一分鐘內(nèi)在表盤(pán)轉(zhuǎn)動(dòng)的度數(shù)也是6度

而時(shí)針呢,一小時(shí)時(shí)針變化為360除以12等于30度,但是有個(gè)問(wèn)題,常理知,時(shí)鐘并不是只有在分針轉(zhuǎn)到12點(diǎn)的時(shí)候才變化,它表盤(pán)里也會(huì)隨著分針的變化而變化(比如說(shuō)1:30,時(shí)針不可能只還停留在1這個(gè)位置,等到2:00的時(shí)候才突然變化)所以這個(gè)角度還需要加上分針對(duì)它的變化。這個(gè)怎么算呢,拿30度除以60現(xiàn)在的系統(tǒng)分鐘數(shù)就可以得到了,也就是0.5現(xiàn)在的分鐘數(shù)就是時(shí)鐘在以分鐘作單位時(shí)轉(zhuǎn)動(dòng)的度數(shù)

30*系統(tǒng)小時(shí)+0.5*系統(tǒng)分鐘

由于這些都是不可變化的,我們來(lái)抽成宏

// 1秒6度(秒針)

#define perSecondA 6

// 1分鐘6度(分針)

#define perMintueA 6

// 1小時(shí)30度(時(shí)針)

#define perHourA 30

// 每分鐘時(shí)針轉(zhuǎn)(30 / 60 °)

#define perMinHourA 0.5

有了這些角度之后,剩下的就很好做了,我們?cè)趘iewDidLoad的里添加一個(gè)定時(shí)器

 [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];

然后在這個(gè)timeChange方法里,設(shè)置時(shí)分秒的旋轉(zhuǎn)形變就可以了,這里注意,CATransform3DMakeRotation這個(gè)接受的弧度而不是角度,我們?cè)俪槌鲆粋€(gè)宏來(lái)將角度轉(zhuǎn)化為弧度

#define angle2radion(angle) ((angle) / 180.0 * M_PI)
- (void)timeChange{
    
    // 獲取當(dāng)前系統(tǒng)時(shí)間
    
    NSCalendar * calender = [NSCalendar currentCalendar];
    
    NSDateComponents * cmp = [calender components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour  fromDate:[NSDate date]];
    
    CGFloat second = cmp.second;
    
    CGFloat secondA = (second * perSecondA) ;
    
    NSInteger minute = cmp.minute;
    
    CGFloat mintuteA = minute * perMintueA ;
    
    NSInteger hour = cmp.hour;
    
    CGFloat hourA = hour * perHourA  + minute * perMinHourA;
    
    _secondLayer.transform = CATransform3DMakeRotation(angle2radion(secondA), 0, 0, 1);

    _mintueLayer.transform = CATransform3DMakeRotation(angle2radion(mintuteA), 0, 0, 1);
    
    _hourLayer.transform = CATransform3DMakeRotation(angle2radion(hourA), 0, 0, 1);
}

做到這里,基本上已經(jīng)大功告成,讓我們運(yùn)行一下

時(shí)鐘已經(jīng)隨著系統(tǒng)時(shí)間轉(zhuǎn)了起來(lái),還可以在修改一些別的樣式,到時(shí)候就看開(kāi)發(fā)者如何發(fā)揮了

本Dome的Github地址
https://github.com/DriverWang/YCClock

最后編輯于
?著作權(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)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 下面教大家用CALayer做時(shí)鐘,不啰嗦了,上圖上代碼。 #import"ViewController.h" #d...
    aven_kang閱讀 977評(píng)論 0 0
  • 聲明:原創(chuàng)作品,轉(zhuǎn)載請(qǐng)注明出處http://www.itdecent.cn/p/c2abd6226897 在上篇文...
    蛇發(fā)女妖閱讀 4,825評(píng)論 6 56
  • CALayer 概念 在iOS中,你能看得見(jiàn)摸得著的東西基本上都是UIView,比如一個(gè)按鈕、一個(gè)文本標(biāo)簽、一個(gè)文...
    iOS_Cqlee閱讀 1,102評(píng)論 8 2
  • 參考:iOS動(dòng)畫(huà)系列之一:通過(guò)實(shí)戰(zhàn)學(xué)習(xí)CALayer和透視的原理。做一個(gè)帶時(shí)分秒指針的時(shí)鐘動(dòng)畫(huà)(上)iOS動(dòng)畫(huà)系列...
    Andy_Ron閱讀 3,406評(píng)論 4 4
  • 這雙鞋是我的指畫(huà)老師虞小風(fēng)送的,我拜師那年,師父師娘特意在武漢差人手工訂制,寄了兩雙。一雙太小,這雙也小,...
    盧果_ea05閱讀 907評(píng)論 4 3

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