使用drawRect伪造UIView动画

zou*_*oul 2 cocoa-touch core-animation uiview ios

我有一个UIView绘制自己使用-drawRect:,我想动画用于绘图的颜色.UIView由于显而易见的原因,基本的动画内容不起作用(drawRect).

我不能简单地使用CAShapeLayer绘制和动画视图内容.我想尝试手动伪造动画,使用计时器或CADisplayLink结合使用setNeedsDisplay.是否有一种相当简单的方法来隐藏通常的UIView动画API 背后的魔力?

例如,假设有一个color我想要动画的属性:

[UIView animateWithDuration:0.2 animations:^{
    [customDrawingView setColor:[UIColor redColor]];
}];
Run Code Online (Sandbox Code Playgroud)

有没有办法"拦截"动画调用来读取动画参数(时间,目标值)并手动处理它们?我不想慌乱UIView.

Mat*_*lak 6

我不得不像你那样做了很多次.一般来说,您可以创建一些类来处理浮点插值或CGPoint插值等内容......并且正确地完成所有操作,但由于整个绘图已经存在,因此它没有多大意义.

所以UIView animateWithDuration这里不起作用,但您可以添加显示链接并手动进行插值.如果没有更改现有代码,最好只添加几个方法:

假设您目前有这样的事情:

- (void)setColor:(UIColor *)color
{
    _color = color;
    [self setNeedsDisplay];
}
Run Code Online (Sandbox Code Playgroud)

现在您可以添加setColorAnimated:并执行所有其他功能:

您需要一些额外的参数(属性),使用您想要的:

UIColor *_sourceColor;
UIColor *_targetColor;
NSDate *_startDate;
NSDate *_endDate;
CADisplayLink *_displayLink;
Run Code Online (Sandbox Code Playgroud)

方法:

- (void)setColorAnimated:(UIColor *)color {
    _sourceColor = self.color; // set start to current color
    _targetColor = color; // destination color
    _startDate = [NSDate date]; // begins currently, you could add some delay if you wish
    _endDate = [_startDate dateByAddingTimeInterval:.3]; // will define animation duration

    [_displayLink invalidate]; // if one already exists
    _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onFrame)]; // create the display link
}
- (UIColor *)interpolatedColor:(UIColor *)sourceColor withColor:(UIColor *)targetColor forScale:(CGFloat)scale {
    // this will interpolate between two colors
    CGFloat r1, g1, b1, a1;
    CGFloat r2, g2, b2, a2;
    [sourceColor getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
    [targetColor getRed:&r2 green:&g2 blue:&b2 alpha:&a2];

    // do a linear interpolation on RGBA. You can use other
    return [UIColor colorWithRed:r1+(r2-r1)*scale
                           green:g1+(g2-g1)*scale
                            blue:b1+(b2-b1)*scale
                           alpha:a1+(a2-a1)*scale];
}
- (void)onFrame {
    // scale is valid between 0 and 1
    CGFloat scale = [[NSDate date] timeIntervalSinceDate:_startDate] / [_endDate timeIntervalSinceDate:_startDate];
    if(scale < .0f) {
        // this can happen if delay is used
        scale = .0f;
    }
    else if(scale > 1.0f)
    {
        // end animation
        scale = 1.0f;
        [_displayLink invalidate];
        _displayLink = nil;
    }
    [self setColor:[self interpolatedColor:_sourceColor withColor:_targetColor forScale:scale]];
}
Run Code Online (Sandbox Code Playgroud)