iOS 動畫篇 (三) CADisplayLink與CoreGraphics實現動畫

來源:互聯網
上載者:User

標籤:self   sele   run   gray   etc   idt   height   instance   一個   

  本文主要介紹利用CoreGraphics和CADisplayLink來實現一個注水動畫。來一個先:

  

  在介紹注水動畫前,先介紹利用CoreGraphics實現進度條的繪製。

  一、扇形進度繪製

  效果:

  代碼如下:

- (instancetype)initWithCoder:(NSCoder *)coder{    self = [super initWithCoder:coder];    if (self) {        self.arcColor = [UIColor cyanColor];    }    return self;}- (void)drawRect:(CGRect)rect {    [super drawRect:rect];    CGContextRef context = UIGraphicsGetCurrentContext();       [self.arcColor setFill];        CGFloat startAngle = -M_PI_2;    CGFloat endAngle  = self.progress * M_PI * 2 + startAngle;       CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2);        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:rect.size.width / 2 startAngle:startAngle endAngle:endAngle clockwise:YES];        CGContextAddPath(context, path.CGPath);    CGContextAddLineToPoint(context, center.x, center.y);        CGContextDrawPath(context, kCGPathFill);}- (void)setProgress:(CGFloat)progress{    NSLog(@"%g", progress);    if (progress > 1) {        progress = 1;    }else if (progress < 0){        progress = 0;    }    _progress = progress;    dispatch_async(dispatch_get_main_queue(), ^{        [self setNeedsDisplay];    });}

原理就是根據不同的進度值不停的重新繪製扇形。

  二、繪製帶邊緣的扇形進度圖

  

  代碼如下:

@implementation ArcWithTrackProgressView- (instancetype)initWithCoder:(NSCoder *)coder{    self = [super initWithCoder:coder];    if (self) {        self.backgroundColor = [UIColor clearColor];        self.trackColor = [UIColor cyanColor];        self.progressColor = [UIColor cyanColor];    }    return self;}- (void)drawRect:(CGRect)rect{    //繪製圈    UIBezierPath *trackPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(rect, 2, 2)];    CGContextRef context = UIGraphicsGetCurrentContext();    CGContextSetLineWidth(context, 0.5);    CGContextAddPath(context, trackPath.CGPath);        [self.trackColor setStroke];    CGContextDrawPath(context, kCGPathStroke);//繪製進度    [self.progressColor setFill];    CGFloat startAngle = - M_PI_2;    CGFloat endAngle = self.progress * 2 * M_PI + startAngle;    CGPoint center = CGPointMake(CGRectGetWidth(rect) / 2, CGRectGetHeight(rect) / 2);    CGFloat radius = CGRectGetHeight(rect) / 2 - 6;//設定半徑    UIBezierPath *progressPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];        CGContextAddPath(context, progressPath.CGPath);    CGContextAddLineToPoint(context, center.x, center.y);    CGContextDrawPath(context, kCGPathFill);}- (void)setProgress:(CGFloat)progress{    NSLog(@"%g", progress);    if (progress > 1) {        progress = 1;    }else if (progress < 0){        progress = 0;    }    _progress = progress;    dispatch_async(dispatch_get_main_queue(), ^{        [self setNeedsDisplay];    });}@end
  三、繪製一個圓環進度

  如下:

  

  此效果分為兩步實現,一部分是繪製圓環,一部分是繪製勾。我在這裡使用的CoreGraphics來繪製環,勾的話是利用CAShapeLayer來實現的。代碼如下:

  

@implementation AnnularProgressView- (instancetype)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        [self commonSetup];    }    return self;}- (instancetype)initWithCoder:(NSCoder *)coder{    self = [super initWithCoder:coder];    if (self) {        [self commonSetup];    }    return self;}- (void)commonSetup{    self.arcColor = [UIColor cyanColor];    self.lineWidth = 5.f;        //設定shapeLayer    CAShapeLayer *tick = [[CAShapeLayer alloc] init];    tick.bounds = self.bounds;    tick.position = CGPointMake(CGRectGetWidth(self.bounds) / 2, CGRectGetHeight(self.bounds) / 2);    CGFloat width = CGRectGetWidth(self.bounds);    CGFloat height = CGRectGetHeight(self.bounds);    UIBezierPath *bezierPath = [[UIBezierPath alloc] init];    [bezierPath moveToPoint:CGPointMake(width * 0.25, height * 0.46)];    [bezierPath addLineToPoint:CGPointMake(width * 0.45, height * 0.71)];    [bezierPath addLineToPoint:CGPointMake(width * 0.78, height * 0.29)];    tick.path = bezierPath.CGPath;    tick.fillColor = [UIColor clearColor].CGColor;    tick.strokeColor = [UIColor cyanColor].CGColor;    tick.strokeStart = 0;    tick.strokeEnd = 0;    tick.lineWidth = self.lineWidth;    tick.lineCap = kCALineJoinRound;        [self.layer addSublayer:tick];        self.tick = tick;}- (void)drawRect:(CGRect)rect {    CGContextRef context = UIGraphicsGetCurrentContext();    CGContextSetLineCap(context, kCGLineCapRound);    CGContextSetLineWidth(context, self.lineWidth);        [self.arcColor setStroke];        //繪製圓環    CGFloat startAngle = -M_PI_2;    CGFloat endAngle  = self.progress * M_PI * 2 + startAngle;    CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2);    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:rect.size.width / 2 - self.lineWidth startAngle:startAngle endAngle:endAngle clockwise:YES];    CGContextAddPath(context, path.CGPath);    CGContextDrawPath(context, kCGPathStroke);        self.tick.strokeEnd = self.progress;//設定勾的進度    }- (void)setProgress:(CGFloat)progress{    NSLog(@"%g", progress);    if (progress > 1) {        progress = 1;    }else if (progress < 0){        progress = 0;    }    _progress = progress;    dispatch_async(dispatch_get_main_queue(), ^{        [self setNeedsDisplay];    });}
  四、注水動畫

  效果:

  

  注水動畫的實現主要是通過正餘弦函數繪製來實現的。正餘弦曲線公式如下:

  正弦函數  

y=Asin(ωx+φ)+k //正弦函數y=Acos(ωx+φ)+k //餘弦函數

其中

A——振幅,當物體作軌跡符合正弦曲線的直線往複運動時,其值為行程的1/2。(ωx+φ)——相位,反映變數y所處的狀態。φ——初相,x=0時的相位;反映在座標繫上則為映像的左右移動。k——偏距,反映在座標繫上則為映像的上移或下移。ω——角速度, 控制正弦周期(單位角度內震動的次數)。  介紹完公式,接下來直接上代碼:
@interface WaveProgressView ()@property (nonatomic, assign) CGFloat initialPhase;//初相@property (nonatomic, strong) CADisplayLink *timer;@end//y=Asin(ωx+φ)+k@implementation WaveProgressView- (instancetype)initWithCoder:(NSCoder *)coder{    self = [super initWithCoder:coder];    if (self) {        [self commonSetup];    }    return self;}- (instancetype)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {       [self commonSetup];    }    return self;}- (void)commonSetup{    CADisplayLink *timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(moveWave:)];    [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];        self.backgroundColor = [UIColor clearColor];}- (void)drawRect:(CGRect)rect{    CGContextRef context = UIGraphicsGetCurrentContext();        UIBezierPath *sinPath = [UIBezierPath bezierPath];    UIBezierPath *cosPath = [UIBezierPath bezierPath];    CGFloat y;    CGFloat amplitude = 5;//振幅    CGFloat palstance = M_PI / self.bounds.size.width;//角速度    CGPoint startPoint = CGPointMake(0, CGRectGetHeight(rect));    [sinPath moveToPoint:startPoint];    [cosPath moveToPoint:startPoint];    //正弦曲線    for (CGFloat x = 0.0 ; x <= rect.size.width; x++) {        y = amplitude * sin(palstance * x + self.initialPhase);        CGPoint point = CGPointMake(x, y + CGRectGetHeight(rect) * (1 - self.progress) - amplitude);        [sinPath addLineToPoint:point];    }        //餘弦曲線    for (int x = 0 ; x <= rect.size.width; x++) {        y = amplitude * cos(palstance * x + self.initialPhase);        CGPoint point = CGPointMake(x, y + CGRectGetHeight(rect) * (1 - self.progress) - amplitude);                [cosPath addLineToPoint:point];    }            CGPoint endPoint = CGPointMake(CGRectGetWidth(rect), CGRectGetHeight(rect));    [sinPath addLineToPoint:endPoint];    [cosPath addLineToPoint:endPoint];    [[UIColor lightGrayColor] setFill];        CGContextAddPath(context, sinPath.CGPath);    CGContextDrawPath(context, kCGPathFill);        [[UIColor cyanColor] setFill];    CGContextAddPath(context, cosPath.CGPath);    CGContextDrawPath(context, kCGPathFill);}- (void)moveWave:(CADisplayLink *)timer{    self.initialPhase += 0.1;    dispatch_async(dispatch_get_main_queue(), ^{        [self setNeedsDisplay];    });    }- (void)setProgress:(CGFloat)progress{    NSLog(@"%g", progress);    if (progress > 1) {        progress = 1;    }else if (progress < 0){        progress = 0;    }    _progress = progress;}- (void)dealloc{    [self.timer invalidate];}

  實現原理:設定好曲線的振幅、角速度,然後根據progress來設定正餘弦曲線的繪製路徑。利用CADisplayLink來不斷的改變曲線的初相來達到曲線移動的效果。

  你可以從這裡下載demo

 

iOS 動畫篇 (三) CADisplayLink與CoreGraphics實現動畫

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.