【问题标题】:CAShapeLayer animation (arc from 0 to final size)CAShapeLayer 动画(从 0 到最终大小的弧线)
【发布时间】:2013-09-16 19:36:34
【问题描述】:

我有一个CAShapeLayer,其中使用UIBezierPath 添加了一个弧。我在 stackoverflow 上看到了几篇帖子(实际上是一篇),但似乎没有一个能给我答案。正如标题中所说,我想为弧线制作动画(是的,它将用于饼图)。

如何完成从“空”弧到完全延伸的动画?有点像弯曲的进度条。通过CoreAnimation真的不可能吗?

这就是我“做”弧线的方式。哦,忽略 cmets 和计算,因为我习惯于逆时针单位圆,而苹果是顺时针方向。弧线看起来很好,我只需要动画:

    //Apple's unit circle goes in clockwise rotation while im used to counter clockwise that's why my angles are mirrored along x-axis
    workAngle = 6.283185307 - DEGREES_TO_RADIANS(360 * item.value / total);

    //My unit circle, that's why negative currentAngle
    [path moveToPoint:CGPointMake(center.x + cosf(outerPaddingAngle - currentAngle) * (bounds.size.width / 2), center.y - (sinf(outerPaddingAngle - currentAngle) * (bounds.size.height / 2)))];

    //Apple's unit circle, clockwise rotation, we add the angles
    [path addArcWithCenter:center radius:120 startAngle:currentAngle endAngle:currentAngle + workAngle clockwise:NO];

    //My unit circle, counter clockwise rotation, we subtract the angles
    [path addLineToPoint:CGPointMake(center.x + cosf(-currentAngle - workAngle) * ((bounds.size.width / 2) - pieWidth), center.y - sinf(-currentAngle - workAngle) * ((bounds.size.height / 2) - pieWidth))];

    //Apple's unit circle, clockwise rotation, addition of angles
    [path addArcWithCenter:center radius:120 - pieWidth startAngle:currentAngle + workAngle endAngle:currentAngle - innerPaddingAngle clockwise:YES];

    //No need for my custom calculations since I can simply close the path
    [path closePath];

    shape = [CAShapeLayer layer];
    shape.frame = self.bounds;
    shape.path = path.CGPath;
    shape.fillColor = kRGBAColor(255, 255, 255, 0.2f + 0.1f * (i + 1)).CGColor; //kRGBAColor is a #defined

    [self.layer addSublayer:shape];


    //THIS IS THE PART IM INTERESTED IN
    if (_shouldAnimate)
    {
        CABasicAnimation *pieAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
        pieAnimation.duration = 1.0;
        pieAnimation.removedOnCompletion = NO;
        pieAnimation.fillMode = kCAFillModeForwards;
        //from and to are just dummies so I dont get errors
        pieAnimation.fromValue = [NSNumber numberWithInt:0]; //from what
        pieAnimation.toValue = [NSNumber numberWithFloat:1.0f]; //to what

        [shape addAnimation:pieAnimation forKey:@"animatePath"];
    }

【问题讨论】:

  • 不好,这会为边框设置动画,以便作品自行绘制,然后用颜色填充(整个填充区域)。我希望它像进度条一样增长。

标签: ios objective-c animation core-animation quartz-core


【解决方案1】:

这是一个基于 CAShapeLayer 的 CALayer 实现:

ProgressLayer.h/m

#import <QuartzCore/QuartzCore.h>

@interface ProgressLayer : CAShapeLayer

-(void) computePath:(CGRect)r;
-(void) showProgress;
@end

#import "ProgressLayer.h"

@implementation ProgressLayer
-(id)init {
    self=[super init];
    if (self) {
        self.path = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 50, 50), 0);
        self.strokeColor = [UIColor greenColor].CGColor;
        self.lineWidth=40;
        self.lineCap = kCALineCapRound;
        self.strokeEnd=0.001;
    }
    return self;
}

-(void) computePath:(CGRect)r {
    self.path = CGPathCreateWithEllipseInRect(r, 0);
}


-(void)showProgress {
    float advance=0.1;
    if (self.strokeEnd>1) self.strokeEnd=0;

    CABasicAnimation * swipe = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    swipe.duration=0.25;
    swipe.fromValue=[NSNumber numberWithDouble:self.strokeEnd];
    swipe.toValue=  [NSNumber numberWithDouble:self.strokeEnd + advance];

    swipe.fillMode = kCAFillModeForwards;
    swipe.timingFunction= [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    swipe.removedOnCompletion=NO;
    self.strokeEnd = self.strokeEnd + advance;
    [self addAnimation:swipe forKey:@"strokeEnd animation"];
}

@end

我将此层用作 UIView 的支持层:

#import "ProgressView.h"
#import "ProgressLayer.h"

@implementation ProgressView


-(id)initWithCoder:(NSCoder *)aDecoder {
    self=[super initWithCoder:aDecoder];
    if (self) {
        [(ProgressLayer *)self.layer computePath:self.bounds];
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    ProgressLayer * l =  self.layer;
    [l showProgress];
}


- (void)drawRect:(CGRect)rect {
    [[UIColor redColor] setStroke];
    UIRectFrame(self.bounds);
}


+(Class)layerClass {
    return [ProgressLayer class];
}

@end

【讨论】:

  • 我们可以改变填充颜色吗?致电[path fill] 不会成功
  • 见 CAShapeLayer fillColor 属性。
【解决方案2】:

在创建动画之前,您需要将形状的 strokeEnd 设置为 0。

然后,使用键@"strokeEnd" 而不是@"path"... CAAnimations 的键通常是您要设置动画的属性的名称。

然后您可以执行以下操作:

[CATransaction begin]
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = 1.0f;
animation.removedOnCompletion = NO;
animation.fromValue = @0; //shorthand for creating an NSNumber
animation.toValue = @1; //shorthand for creating an NSNumber
[self addAnimation:animation forKey:@"animateStrokeEnd"];
[CATransaction commit];

【讨论】:

    【解决方案3】:

    您必须使用正确的键。 “path”和“animatePath”对它没有任何意义——你必须使用“strokeEnd”作为你的键/键路径。如果您需要调整填充颜色,请使用 fillColor。完整列表在这里:

    https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CAShapeLayer_class/Reference/Reference.html

    【讨论】:

    • 是的,我知道我必须使用正确的键,但我只是不知道使用哪个键,因为我想要一个“弯曲的进度条”填充动画。
    • @Majster 几乎可以肯定是strokeEnd。创建一条您想要的曲线路径,将其设置为以任何宽度为您提供所需条形的描边,然后为描边末端设置动画。当该属性为 0 时,图层将绘制路径的前 0%。当它为 0.5 时,图层将绘制路径的前 50%,等等。
    • 其实不是。 Stroke 为形状的外线设置动画。我希望整个形状都长大 - 包括填充。当你写这篇文章时,你确实在我脑海中冒出了一个想法——我尝试将 lineWidth 设置为 50,并使实际的填充区域非常小,以至于它几乎不可见,但是外角和内角没有对齐。希望你明白我的意思。如果您确实有解决方案,请发布包含一些代码的答案,以便我可以看到哪里出错了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    相关资源
    最近更新 更多