iOS 動畫 —— 太極陰陽圖

以小 Demo 形式繼續學習動畫,同時再次發現我們中國文化的強大啊,國外有好多詞根本沒有,像太極通常的翻譯的就是 Tai Ji,哈哈

截斷的旋轉太極圖
#import "TaiJiView.h"

@implementation TaiJiView {
    NSTimer *_timer;
    CGFloat _currentRotate; // 當前旋轉偏移
}

- (instancetype)initWithFrame:(CGRect)frame {
    
    self = [super initWithFrame:frame];
    if (self) {
        _currentRotate = 0.0;
        self.backgroundColor = [UIColor clearColor];
        _timer = [NSTimer scheduledTimerWithTimeInterval:0.05f target:self selector:@selector(updateRotate) userInfo:nil repeats:YES];
    }
    return self;
}

- (void)dealloc {
    [_timer invalidate];
    _timer = nil;
}

- (void)updateRotate {
    _currentRotate += 0.01;
    // setNeedsDisplay會調用自動調用drawRect方法
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {

    // 獲取中心點
    CGFloat x = self.frame.size.width/2;
    CGFloat y = self.frame.size.height/2;
    // 獲取真正的半徑
    CGFloat radius = MIN(x, y);
    // 設置當前的偏移量
    CGFloat runAngle = M_PI*_currentRotate;
    if (runAngle >= 2*M_PI) {
        runAngle -= 2*M_PI;
    }
    // 開始畫
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 經典的黑白顏色
    CGColorRef  whiteColor =[[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f] CGColor];
    CGColorRef  blackColor =[[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f] CGColor];
    /*
     CGContextAddArc(CGContextRef __nullable c, CGFloat x, CGFloat y,
     CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
     注意: startAngle: 開始角度
           endAngle :結束角度
           clockwise: 0 為順時針,1 逆時針
     **/
    
    // 獲取下部分白色的半圓(假設第一次時)
    CGContextSetFillColor(context, CGColorGetComponents(whiteColor));
    CGContextAddArc(context, x, y, radius, 0+runAngle, M_PI+runAngle, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);
    
    // 獲取上部分黑色的半圓
    CGContextSetFillColor(context, CGColorGetComponents( blackColor));
    CGContextAddArc(context, x, y, radius, M_PI+runAngle, M_PI*2+runAngle, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);

    //再畫右邊上部分白色的半圓
    CGContextSetFillColor(context, CGColorGetComponents( whiteColor));
    CGContextAddArc(context, x+radius/2*cos(runAngle), y+radius/2*sin(runAngle), radius/2, M_PI+runAngle, M_PI*2+runAngle, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);

    // 再畫左邊下部分黑色的半圓
    CGContextSetFillColor(context, CGColorGetComponents(blackColor));
    CGContextAddArc(context, x-radius/2*cos(runAngle), y-radius/2*sin(runAngle), radius/2, 0+runAngle, M_PI+runAngle, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);

    // 再畫兩條半徑,相當于分割線
    CGContextSetStrokeColorWithColor(context, whiteColor);
    CGContextMoveToPoint(context, x+radius*cos(runAngle), y+radius*sin(runAngle));
    CGContextAddLineToPoint(context, x, y);
    CGContextStrokePath(context);

    CGContextSetStrokeColorWithColor(context, blackColor);
    CGContextMoveToPoint(context, x-radius*cos(runAngle), y-radius*sin(runAngle));
    CGContextAddLineToPoint(context, x, y);
    CGContextStrokePath(context);

    // 再下面就是兩個小圓啦
    CGContextSetFillColor(context, CGColorGetComponents( whiteColor));
    CGContextAddArc(context, x-radius/2*cos(runAngle), y-radius/2*sin(runAngle), radius/4, 0, M_PI*2, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);
    
    CGContextSetFillColor(context, CGColorGetComponents( blackColor));
    CGContextAddArc(context, x+radius/2*cos(runAngle), y+radius/2*sin(runAngle), radius/4, 0, M_PI*2, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);
}

@end

注意一:標顏色時,上面一種獲取顏色在此處是無效的

 CGColorRef  blackColor = [UIColor blackColor].CGColor;
 CGColorRef  blackColor =[[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f] CGColor];

通過下面這些注釋,我們可以理解類似[UIColor blackColor]獲取顏色值,實際上相當是相當獲取緩存下來的。

// Some convenience methods to create colors.  
// These colors will be as calibrated as possible.
// These colors are cached.

而上述第一種情況的時候,可能并沒能拿到緩存的顏色值,或者說此處是初始化CGColorRef ,并不是簡單的獲取顏色值 ,所以無效。

注意二: setNeedsDisplay

異步執行的方法
一旦調用setNeedsDisplay就會調用自動調用drawRect方法
而setNeedsLayout會默認調  用layoutSubViews,就可以處理子視圖中的一些數據。

可以說,setNeedsDisplay方便繪圖,而layoutSubViews方便更新數據。

注意三: CGContextAddArc 方法

CGContextAddArc(CGContextRef __nullable c, CGFloat x, CGFloat y,
CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)
    注意: startAngle: 開始角度
           endAngle :結束角度
           clockwise: 0 為順時針,1 為逆時針

PS:場景來自【iOS開發范例實戰寶典.進階篇】。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容