【问题标题】:IOS : Animate transformation from a line to a bezier curveIOS:从直线到贝塞尔曲线的动画转换
【发布时间】:2013-01-28 21:00:09
【问题描述】:

我想将一条曲线动画成贝塞尔曲线(从“_”到“n”),是否有某个库可以帮助我做到这一点?

我知道如何使用 UIBezierPath 绘制贝塞尔曲线,我可以快速重绘并逐步进行转换,但如果已经这样做了,那就太酷了 :-)

【问题讨论】:

    标签: ios core-graphics bezier uibezierpath nsbezierpath


    【解决方案1】:

    我可能会用CADisplayLink 做点什么。例如,您可以在视图控制器中使用CAShapeLayer 执行此操作,例如:

    #import "ViewController.h"
    #import <QuartzCore/QuartzCore.h>
    
    @interface ViewController ()
    
    @property (nonatomic) CFTimeInterval firstTimestamp;
    @property (nonatomic, strong) CAShapeLayer *shapeLayer;
    @property (nonatomic, strong) CADisplayLink *displayLink;
    @property (nonatomic) NSUInteger loopCount;
    
    @end
    
    static CGFloat const kSeconds = 5.0;
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        [self addShapeLayer];
        [self startDisplayLink];
    }
    
    - (void)addShapeLayer
    {
        self.shapeLayer = [CAShapeLayer layer];
        self.shapeLayer.path = [[self pathAtInterval:0.0] CGPath];
        self.shapeLayer.fillColor = [[UIColor clearColor] CGColor];
        self.shapeLayer.lineWidth = 3.0;
        self.shapeLayer.strokeColor = [[UIColor redColor] CGColor];
        [self.view.layer addSublayer:self.shapeLayer];
    }
    
    - (void)startDisplayLink
    {
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
        [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    
    - (void)stopDisplayLink
    {
        [self.displayLink invalidate];
        self.displayLink = nil;
    }
    
    - (void)handleDisplayLink:(CADisplayLink *)displayLink
    {
        if (!self.firstTimestamp)
            self.firstTimestamp = displayLink.timestamp;
    
        self.loopCount++;
    
        NSTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
    
        self.shapeLayer.path = [[self pathAtInterval:elapsed] CGPath];
    
        if (elapsed >= kSeconds)
        {
            [self stopDisplayLink];
            self.shapeLayer.path = [[self pathAtInterval:0] CGPath];
    
            self.statusLabel.text = [NSString stringWithFormat:@"loopCount = %.1f frames/sec", self.loopCount / kSeconds];
        }
    }
    
    - (UIBezierPath *)pathAtInterval:(NSTimeInterval) interval
    {
        UIBezierPath *path = [UIBezierPath bezierPath];
    
        [path moveToPoint:CGPointMake(0, self.view.bounds.size.height / 2.0)];
    
        CGFloat fractionOfSecond = interval - floor(interval);
    
        CGFloat yOffset = self.view.bounds.size.height * sin(fractionOfSecond * M_PI * 2.0);
    
        [path addCurveToPoint:CGPointMake(self.view.bounds.size.width, self.view.bounds.size.height / 2.0)
                controlPoint1:CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0 - yOffset)
                controlPoint2:CGPointMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0 + yOffset)];
    
        return path;
    }
    
    @end
    


    或者,如果您想通过子类化 UIView 来实现,您可以这样做:

    #import "View.h"
    #import <QuartzCore/QuartzCore.h>
    
    @interface View ()
    
    @property (nonatomic, strong) CADisplayLink *displayLink;
    @property (nonatomic) CFTimeInterval firstTimestamp;
    @property (nonatomic) CFTimeInterval displayLinkTimestamp;
    @property (nonatomic) NSUInteger loopCount;
    
    @end
    
    static CGFloat const kSeconds = 5.25;
    
    @implementation View
    
    - (id)initWithCoder:(NSCoder *)aDecoder
    {
        self = [super initWithCoder:aDecoder];
        if (self) {
            [self startDisplayLink];
        }
    
        return self;
    }
    
    - (void)startDisplayLink
    {
        _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
        [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    
    - (void)stopDisplayLink
    {
        [self.displayLink invalidate];
        self.displayLink = nil;
    }
    
    - (void)handleDisplayLink:(CADisplayLink *)displayLink
    {
        if (!self.firstTimestamp)
            self.firstTimestamp = displayLink.timestamp;
    
        self.displayLinkTimestamp = displayLink.timestamp;
    
        self.loopCount++;
    
        [self setNeedsDisplayInRect:self.bounds];
    
        NSTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
    
        if (elapsed >= kSeconds)
        {
            [self stopDisplayLink];
            self.displayLinkTimestamp = self.firstTimestamp + kSeconds;
            [self setNeedsDisplayInRect:self.bounds];
            self.statusLabel.text = [NSString stringWithFormat:@"loopCount = %.1f frames/sec", self.loopCount / kSeconds];
        }
    }
    
    - (UIBezierPath *)pathAtInterval:(NSTimeInterval) interval
    {
        UIBezierPath *path = [UIBezierPath bezierPath];
    
        [path moveToPoint:CGPointMake(0, self.bounds.size.height / 2.0)];
    
        CGFloat fractionOfSecond = interval - floor(interval);
    
        CGFloat yOffset = self.bounds.size.height * sin(fractionOfSecond * M_PI * 2.0);
    
        [path addCurveToPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height / 2.0)
                controlPoint1:CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0 - yOffset)
                controlPoint2:CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0 + yOffset)];
    
        return path;
    }
    
    
    - (void)drawRect:(CGRect)rect
    {
        NSTimeInterval elapsed = (self.displayLinkTimestamp - self.firstTimestamp);
    
        UIBezierPath *path = [self pathAtInterval:elapsed];
    
        [[UIColor redColor] setStroke];
        path.lineWidth = 3.0;
        [path stroke];
    }
    
    @end
    

    我测试了子类UIView 以及视图控制器,它们都产生了大约 60 帧/秒。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-27
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    相关资源
    最近更新 更多