使用drawRect伪造UIView动画

时间:2014-11-05 07:37:43

标签: ios cocoa-touch uiview core-animation

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

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

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

[UIView animateWithDuration:0.2 animations:^{
    [customDrawingView setColor:[UIColor redColor]];
}];

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

2 个答案:

答案 0 :(得分:6)

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

因此UIView animateWithDuration无效,但您可以添加显示链接并手动进行插值。如果没有更改现有代码,最好只添加几个方法:

假设你现在有这样的东西:

- (void)setColor:(UIColor *)color
{
    _color = color;
    [self setNeedsDisplay];
}

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

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

UIColor *_sourceColor;
UIColor *_targetColor;
NSDate *_startDate;
NSDate *_endDate;
CADisplayLink *_displayLink;

方法:

- (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]];
}

答案 1 :(得分:-1)

通过drawRect创建的动画(淡入)新帧

- (void)drawRect:(CGRect)rect {
    CABasicAnimation *animation;
    animation = [CABasicAnimation animation];
    [animation setDuration:0.5];
    [[self layer] addAnimation:animation forKey:@"contents"];

   .. your stuff here

}