animation - 7

本文介绍了一个基于GitHub项目的iOS动画演示,重点讲解了如何使用CADisplayLink进行高效的动画更新,并通过spring动画实现了平滑过渡效果。文章深入剖析了BlockView类的实现细节,包括动画启动、绘制过程及动画完成的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天我们来学习一下,GitHub上一个很好的动画演示:

https://github.com/Glow-Inc/CADisplayLinkDemo



源码可以直接去下载。


其中用到的主要的动画曲线是spring 动画。

http://www.renfei.org/blog/ios-8-spring-animation.html

参考这篇,可以了解参数的意义


比起上面的这个更值得讲的是这个BlockView的实现:

#import "BlockView.h"

@interface BlockView()

@property (strong, nonatomic) CADisplayLink *displayLink;
@property (nonatomic) CGFloat from;
@property (nonatomic) CGFloat to;
@property (nonatomic) BOOL animating;

@end

@implementation BlockView

- (void)startAnimationFrom:(CGFloat)from to:(CGFloat)to
{
    self.from = from;
    self.to = to;
    self.animating = YES;
    if (self.displayLink == nil) {
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
        
        [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop]
                               forMode:NSDefaultRunLoopMode];
    }
}

- (void)completeAnimation
{
    self.animating = NO;
    [self.displayLink invalidate];
    self.displayLink = nil;
}

- (void)tick:(CADisplayLink *)displayLink
{
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    CALayer *layer =self.layer.presentationLayer;
    
    CGFloat progress = 1;
    
    if (!self.animating) {
        progress = 1;
    } else {
        progress = 1 - (layer.position.y - self.to) / (self.from - self.to);
    }
    
    CGFloat height = CGRectGetHeight(rect);
    CGFloat deltaHeight = height / 2 * (0.5 - fabs(progress - 0.5));
    NSLog(@"delta:%f", deltaHeight);
    
    CGPoint topLeft = CGPointMake(0, deltaHeight);
    CGPoint topRight = CGPointMake(CGRectGetWidth(rect), deltaHeight);
    CGPoint bottomLeft = CGPointMake(0, height);
    CGPoint bottomRight = CGPointMake(CGRectGetWidth(rect), height);
    
    UIBezierPath* path = [UIBezierPath bezierPath];
    [[UIColor blueColor] setFill];
    [path moveToPoint:topLeft];
    [path addQuadCurveToPoint:topRight controlPoint:CGPointMake(CGRectGetMidX(rect), 0)];
    [path addLineToPoint:bottomRight];
    [path addQuadCurveToPoint:bottomLeft controlPoint:CGPointMake(CGRectGetMidX(rect), height - deltaHeight)];
    [path closePath];
    [path fill];
}

@end



CADisplayLink

是相当于动画中的计时器,我们看可以看到:

- (void)startAnimationFrom:(CGFloat)from to:(CGFloat)to
{
    self.from = from;
    self.to = to;
    self.animating = YES;
    if (self.displayLink == nil) {
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
        
        [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop]
                               forMode:NSDefaultRunLoopMode];
    }
}


- (void)tick:(CADisplayLink *)displayLink
{
    [self setNeedsDisplay];
}

不断去调用setNeesDisplay,众所周知,就是调起重绘:

- (void)drawRect:(CGRect)rect
{
    CALayer *layer =self.layer.presentationLayer;
    
    CGFloat progress = 1;
    
    if (!self.animating) {
        progress = 1;
    } else {
        progress = 1 - (layer.position.y - self.to) / (self.from - self.to);
    }
    
    CGFloat height = CGRectGetHeight(rect);
    CGFloat deltaHeight = height / 2 * (0.5 - fabs(progress - 0.5));
    NSLog(@"delta:%f", deltaHeight);
    
    CGPoint topLeft = CGPointMake(0, deltaHeight);
    CGPoint topRight = CGPointMake(CGRectGetWidth(rect), deltaHeight);
    CGPoint bottomLeft = CGPointMake(0, height);
    CGPoint bottomRight = CGPointMake(CGRectGetWidth(rect), height);
    
    UIBezierPath* path = [UIBezierPath bezierPath];
    [[UIColor blueColor] setFill];
    [path moveToPoint:topLeft];
    [path addQuadCurveToPoint:topRight controlPoint:CGPointMake(CGRectGetMidX(rect), 0)];
    [path addLineToPoint:bottomRight];
    [path addQuadCurveToPoint:bottomLeft controlPoint:CGPointMake(CGRectGetMidX(rect), height - deltaHeight)];
    [path closePath];
    [path fill];
}

这里用了presentationLayer获取position,并且计算差值,得到左上,右上,左下,右下四个点

然后用贝塞尔曲线去画出当前的曲线效果。


所以一个良好的绘图加动画我们就可以参考上面的实现。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值