iOS和QUOT;擦除"与CAShapeLayer动画绘制 [英] iOS "erase" drawing with CAShapeLayer animated

查看:670
本文介绍了iOS和QUOT;擦除"与CAShapeLayer动画绘制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个自己绘制动画的值更改一个圆形标志。

我用 CAShapeLayer 动画绘制。到目前为止,我得到了它从一开始每次,它按预期工作绘制自身。现在我想,使其更加时尚和向前画它,擦除取决于如果新的值大于previous更高或更低。我不知道如何实现擦除一部分。有一个背景,所以我不能只是与白色顶部绘制。下面是一个图像以便更好地了解它的外观。

任何想法擦除部如何实现?这里有一些解决方案上等等类似的问题,但这些不涉及动画。

我用这个code得出:

   - (无效)drawCircleAnimatedWithStartAngle:(CGFloat的)由startAngle
                            endAngle:(CGFloat的)endAngle
                               颜色:(*的UIColor)颜色
                              半径:(INT)半径
                           的lineWidth:(INT)的lineWidth {
CAShapeLayer *圈= [CAShapeLayer层]
circle.name = @circleLayer    circle.path =(UIBezierPath bezierPathWithArcCenter:CGPointMake(半径,半径)半径:半径-1由startAngle:startAngle开始endAngle:endAngle顺时针:YES] .CGPath);//配置圆的apperence
circle.fillColor =的UIColor clearColor] .CGColor;
circle.strokeColor = [的UIColor colorWithRed:19.0 / 255绿色:167.0 / 255蓝:191.0 / 255阿尔法:1] .CGColor;
circle.lineWidth =的lineWidth;//添加到父层
对(在self.circleView.layer.sublayers的CALayer *层){
    如果([layer.name isEqualToString:@circleLayer]){
        [层removeFromSuperlayer]
        打破;
    }
}[self.circleView.layer addSublayer:社交圈;
circle.zPosition = 1;
//配置动画
CABasicAnimation * drawAnimation = [CABasicAnimation animationWithKeyPath:@strokeEnd];
drawAnimation.duration = 0.5;
drawAnimation.repeatCount = 1.0; //动画只有一次..//从行程的任何部分被动画吸引到正在制定的整个行程
drawAnimation.fromValue = [NSNumber的numberWithFloat:0.0];
drawAnimation.toValue = [NSNumber的numberWithFloat:1.0F];drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];//动画添加到圈子
[圈addAnimation:drawAnimation forKey:@drawCircleAnimation];}


解决方案

我能够从你在做什么这样做在一个稍微不同的方式。相反,绘制一定长度的圆弧,我做了我的道路了一大圈,但只有它的动画一部分的方式。你会发现,我用的是presentation层的strokeEnd得到toValue,因此,如果一个动画正在进行当你需要改变最终strokeEnd的价值,它会从所在的路径正在绘制的开始。这里是我的视图控制器的code;轮廓层绘制的灰色圆圈,类似你有你的形象是什么。我加了5按键我的观点(用于测试),其标签被用来改变动画的最终行程值,

  @implementation的ViewController {
    UIView的* circleView;
    RDShapeLayer *循环;
} - (无效)viewDidLoad中{
    [超级viewDidLoad中];
    circleView = [[UIView的的alloc] initWithFrame:方法CGRectMake(100,100,200,200)];
    CALayer的* outlineLayer = [CALayer的新]
    outlineLayer.frame = circleView.bounds;
    outlineLayer.borderWidth = 2;
    outlineLayer.borderColor =的UIColor lightGrayColor] .CGColor;
    outlineLayer.cornerRadius = circleView.frame.size.width / 2.0;
    [circleView.layer addSublayer:outlineLayer];
    [self.view addSubview:circleView];    圈= [[RDShapeLayer页头] initWithFrame:方法circleView.bounds颜色:[的UIColor blueColor] .CGColor的lineWidth:4];
    [circleView.layer addSublayer:社交圈;
}
- (无效)animateToPercentWayAround:(CGFloat的){百分之    circle.strokeEnd =百分比/ 100.0;
    CABasicAnimation * drawAnimation = [CABasicAnimation animationWithKeyPath:@strokeEnd];
    drawAnimation.duration = 1.0;
    drawAnimation.fromValue = @([圈presentationLayer strokeEnd。]);
    drawAnimation.toValue = @(百分比/ 100.0);    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [圈addAnimation:drawAnimation forKey:@drawCircleAnimation];
}
- (IBAction为)changeStroke:(UIButton的*){发件人
    [个体经营animateToPercentWayAround:sender.tag];
}

这是code的子类CAShapeLayer,

   - (instancetype)initWithFrame:方法(的CGRect)框架颜色:(CGColorRef)颜色的lineWidth:(CGFloat的)的lineWidth {
    如果(自= [超级初始化]){        self.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(帧,1,1)] CGPath;
        self.fillColor =的UIColor clearColor] .CGColor;
        self.strokeColor =颜色;
        self.lineWidth =的lineWidth;
        self.strokeStart = 0;
        self.strokeEnd = 0;
    }
    返回自我;
}

I'm trying to implement a circular indicator that draws itself with animation as values change.

I use CAShapeLayer to draw with animation. So far I got it to draw itself from the beginning each time, it works as intended. Now I want to make it more sleek and draw it forward and "erase" depending on if the new value is greater or lower than previous. I'm not sure how to implement the erasing part. There's a background so I cant just draw on top with white colour. Here's an image to better understand how it looks.

Any ideas how erasing part could be achieved? There's some solutions here on SO on similar problems, but those involve no animation.

I use this code to draw:

- (void)drawCircleAnimatedWithStartAngle:(CGFloat)startAngle
                            endAngle:(CGFloat)endAngle
                               color:(UIColor *)color
                              radius:(int)radius
                           lineWidth:(int)lineWidth {


CAShapeLayer *circle = [CAShapeLayer layer];
circle.name = @"circleLayer";

    circle.path = ([UIBezierPath bezierPathWithArcCenter:CGPointMake(radius, radius) radius:radius-1 startAngle:startAngle endAngle:endAngle clockwise:YES].CGPath);

// Configure the apperence of the circle
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor colorWithRed:19.0/255 green:167.0/255 blue:191.0/255 alpha:1].CGColor;
circle.lineWidth = lineWidth;

// Add to parent layer
for (CALayer *layer in self.circleView.layer.sublayers) {
    if ([layer.name isEqualToString:@"circleLayer"]) {
        [layer removeFromSuperlayer];
        break;
    }
}

[self.circleView.layer addSublayer:circle];
circle.zPosition = 1;


// Configure animation
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
drawAnimation.duration            = 0.5; 
drawAnimation.repeatCount         = 1.0;  // Animate only once..

// Animate from no part of the stroke being drawn to the entire stroke being drawn
drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
drawAnimation.toValue   = [NSNumber numberWithFloat:1.0f];

drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

// Add the animation to the circle
[circle addAnimation:drawAnimation forKey:@"drawCircleAnimation"];

}

解决方案

I was able to do this in a slightly different way from what you're doing. Instead of drawing an arc of a certain length, I made my path a full circle, but only animate it part way. You will notice that I use the presentation layer's strokeEnd to get the toValue, so that if an animation is in progress when you need to change the value of the final strokeEnd, it will start from where the path is currently drawn. Here is the code in my view controller; outline layer draws the gray circle, similar to what you have in your image. I added 5 buttons to my view (for testing) whose tags are used to change the final stroke value of the animation,

@implementation ViewController {
    UIView *circleView;
    RDShapeLayer *circle;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    circleView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
    CALayer *outlineLayer = [CALayer new];
    outlineLayer.frame = circleView.bounds;
    outlineLayer.borderWidth = 2;
    outlineLayer.borderColor = [UIColor lightGrayColor].CGColor;
    outlineLayer.cornerRadius = circleView.frame.size.width/2.0;
    [circleView.layer addSublayer:outlineLayer];
    [self.view addSubview:circleView];

    circle = [[RDShapeLayer alloc] initWithFrame:circleView.bounds color:[UIColor blueColor].CGColor lineWidth:4];
    [circleView.layer addSublayer:circle];
}


-(void)animateToPercentWayAround:(CGFloat) percent {

    circle.strokeEnd = percent/100.0;
    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.duration = 1.0;
    drawAnimation.fromValue = @([circle.presentationLayer strokeEnd]);
    drawAnimation.toValue   = @(percent/100.0);

    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [circle addAnimation:drawAnimation forKey:@"drawCircleAnimation"];
}


- (IBAction)changeStroke:(UIButton *)sender {
    [self animateToPercentWayAround:sender.tag];
}

This is the code for the subclassed CAShapeLayer,

-(instancetype)initWithFrame:(CGRect) frame color:(CGColorRef) color lineWidth:(CGFloat) lineWidth {
    if (self = [super init]) {

        self.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(frame, 1, 1)].CGPath;
        self.fillColor = [UIColor clearColor].CGColor;
        self.strokeColor = color;
        self.lineWidth = lineWidth;
        self.strokeStart = 0;
        self.strokeEnd = 0;
    }
    return self;
}

这篇关于iOS和QUOT;擦除"与CAShapeLayer动画绘制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆