【问题标题】:Faking UIView animation with drawRect用 drawRect 伪造 UIView 动画
【发布时间】:2015-01-01 07:58:03
【问题描述】:

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

我不能简单地使用CAShapeLayer 来绘制视图内容并为其设置动画。我想尝试手动伪造动画,使用计时器或CADisplayLinksetNeedsDisplay 结合使用。有没有一种相当简单的方法可以将这种魔力隐藏在通常的 UIView 动画 API 后面?

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

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

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

【问题讨论】:

  • 谢谢。不过,那是在使用CALayers 吗?我有现有的绘图代码,看起来很难重构为CALayer,我只需几个步骤就可以轻松地使用简单的动画。这就是为什么我想尝试使用现有的 drawRect 实现。
  • 虽然我思考的时间越长,我就越相信CALayer 是正确的选择。
  • 您也可以在图层中进行自定义核心图形绘制。
  • 我已经尝试过CALayer 方法。 CALayer 没有动画颜色,所以我尝试了CAShapeLayer。但是CAShapeLayer 只支持单一路径,我需要一个具有不同笔触、填充和选项的复杂路径。我可以用普通的CALayer 来绘制它,但是我必须手动添加动画支持。最后,使用CADisplayLinksetNeedsDisplay 对现有绘图代码进行动画处理要容易得多。我必须添加显式动画 API 调用(setProperty:duration:),但我可以接受。

标签: ios cocoa-touch uiview core-animation


【解决方案1】:

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

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

   .. your stuff here

}

【讨论】:

    【解决方案2】:

    我不得不像你那样做很多次。一般来说,您可以创建一些类来处理诸如浮点插值或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]];
    }
    

    【讨论】:

    • CALayer 代码结果让我很头疼,所以我最终按照这里的建议手动制作了动画。我仍然很好奇是否可以将实现隐藏在隐式 UIView 动画 API 后面。
    • 可能是,但我有点怀疑。您需要从动画本身获得的是“插值器”,值范围从 0 到 1。但很难说 Apple 在后台做了什么,是否有一个包含动画参数的类,例如 source 和目标或视图包含它们自己。无论如何,这种方法对于除了最简单的动画之外的任何东西都是无用的。除非您在多个地方需要此程序,否则我认为甚至不值得花时间研究。
    • 我很乐意得到目标值和持续时间。
    • 如果这是针对特定视图的,只需将其子类化并覆盖 animateWithDuration 方法。然后调用我在此答案中发布的相同方法。
    • 天啊,我没想到,谢谢。问题是隐式动画 API 可能会在视图层次结构更高的地方调用,即。在视图的超级视图中。我猜它可以解决,但我无法将魔法封装在需要它的类中。这可能不值得麻烦。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-06
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 2018-06-28
    • 1970-01-01
    相关资源
    最近更新 更多