绘制线条的动画化

7
我正在尝试通过以下方式来动画绘制一条线:

.h

CAShapeLayer *rootLayer;
CAShapeLayer *lineLayer;
CGMutablePathRef path;

.m

 path = CGPathCreateMutable();
 CGPathMoveToPoint(path, nil, self.frame.size.width/2-100, 260);
 CGPathAddLineToPoint(path, nil, self.frame.size.width/2+100.0, 260);    
 CGPathCloseSubpath(path);

 self.rootLayer = [CALayer layer];
 rootLayer.frame = self.bounds;
[self.layer addSublayer:rootLayer];

 self.lineLayer = [CAShapeLayer layer];
[lineLayer setPath:path];
[lineLayer setFillColor:[UIColor redColor].CGColor];
[lineLayer setStrokeColor:[UIColor blueColor].CGColor];
[lineLayer setLineWidth:1.5];
[lineLayer setFillRule:kCAFillRuleNonZero];
[rootLayer addSublayer:lineLayer];

[self performSelector:@selector(startTotalLine) withObject:nil afterDelay:1.5];

- (void)startTotalLine
{    
      CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"animatePath"];
      [animation setDuration:3.5];
       animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
      [animation setAutoreverses:NO];
      [animation setFromValue:(id)path];
      [animation setToValue:(id)path];
      [lineLayer addAnimation:animation forKey:@"animatePath"];    
}

在调用 startTotalLine 方法之前,线已经被画出来了。 此外,startTotalLine 方法不会影响这条线。
我希望它能够从右到左动态地绘制这条线。
3个回答

6

我会使用动画属性来完成它。

为了实现这个目标,我会创建一个自定义的 CALayer 类——让我们称之为 LineLayer。定义一个 startPoint 属性和一个 length 属性。然后,我会将 length 属性配置为“可动画的”。

以下是该代码:

// LineLayer.h
@interface LineLayer: CALayer

@property (nonatomic, assign) int length;
// This was omitted from the SO code snippet.
@property (nonatomic, assign) CGPoint startPoint;

@end

// LineLayer.m
@implementation LineLayer

@synthesize length = _length;
// This was omitted from the SO code snippet.
@synthesize startPoint= _startPoint;

- (id) initWithLayer:(id)layer 
{
    if(self = [super initWithLayer:layer]) 
    {
        if([layer isKindOfClass:[LineLayer class]]) 
        {
            // This bit is required for when we CA is interpolating the values.
            LineLayer *other = (LineLayer*)layer;
            self.length = other.length;
            self.startPoint = other.startPoint; // This was omitted.
        }
    }
    return self;
}

+ (BOOL)needsDisplayForKey:(NSString *)key 
{
    if ([key isEqualToString:@"length"]) {
        return YES;
    }
    return [super needsDisplayForKey:key];
}

- (void) setLength:(int)newLength
{
    if (newLength < 0) {
        return; // Fail early.
    }
    _length = newLength; 
    [self setNeedsDisplay]; 
} 

/*
    This should have been drawInContext:(CGContextRef)context
    - (void) drawRect:(CGRect) rect 
*/
- (void) drawInContext:(CGContextRef)context
{
    //...Do your regular drawing here.

    // This was omitted from the SO code snippet.
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    CGContextSetLineWidth(context, 2);
    CGContextMoveToPoint(context, _startPoint.x, _startPoint.y);
    CGContextAddLineToPoint(context, _startPoint.x + _length, _startPoint.y);
    CGContextStrokePath(context);
}

@end

然后在您的视图控制器中,您可以像这样使用LineLayer

- (void)viewDidLoad
{
    [super viewDidLoad];

    LineLayer *lineLayer = [LineLayer new];

    // This was omitted from the SO code snippet.
    lineLayer.frame = CGRectMake(0, 0, 320, 480);
    [lineLayer setNeedsDisplay];
    // ---

    lineLayer.startPoint = CGPointMake(0, 100);
    lineLayer.length = 0;

    [self.view.layer addSublayer:lineLayer];

    // Now animate the changes to the length property
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"length"];
    anim.duration = 5; // Change should table about 5 mins.
    anim.fromValue = [NSNumber numberWithInt:0];
    anim.toValue = [NSNumber numberWithInt:200];

    [lineLayer addAnimation:anim forKey:@"animateLength"];
    lineLayer.length = 200;
    //Do clean up below...
}

愉快的编码 :)


@Danich 很好,你发现了错别字。我已经更新了代码。谢谢。 - haroldcampbell
@Danich,如果您需要一个可运行的示例项目,请让我知道。 - haroldcampbell
不用了,谢谢,它已经在工作了)现在我明白了,@user546074试图实现什么... - DanSkeel

4
我认为实现你想要的最简单的方法是展示一个高度为1.5像素的UIView并且动画它的宽度。如果我不清楚,请问我。
我认为你的代码无法工作,因为你的变量path不是一个图层属性。请阅读手册
CABasicAnimation为图层属性提供基本的单关键帧动画功能。
而且你在这里做了一些奇怪的事情:
[animation setFromValue:(id)path];
[animation setToValue:(id)path];

编辑: 我偶然发现了一篇文章,明白了您想要实现的目标!现在我认为您失败的原因是您可以动画化不改变点数的路径。现在我认为您可以创建一个具有两个点的路径线。首先它们在同一个位置,另一条路径是您想要最终到达的线。现在从第一条路径到第二条路径进行动画。我认为这应该可以实现,但我不确定。

编辑: 绝对需要这个人的代码。Git链接


实际上这是可能的,但我想学习如何使用Quartz来实现。 - jkigel
据我理解,这些技术是为一段时间内的绘图进行优化的。比如说绘制一些漂亮的静态视图就可以了。如果你想要做动画,应该使用GLKView。这就是我现在的看法。或者使用动画块。 - DanSkeel
也许我错了,但我认为无法对线条进行动画处理? - DanSkeel
谢谢您的回答,我想到了一种新的方法:将线条的颜色设置为白色/透明,然后使用动画将其颜色更改为蓝色,例如,动画应从左到右更改其颜色。 - jkigel
嗯,这是个好主意,你可以把你的代码作为答案发布,这对大家都有用。 - DanSkeel

1
这是我的解决方案,使用“UIBezierPath”、“CAShapeLayer”和属性“strokeEnd”来处理您的情况:
.m文件
@synthesize shapeLayer;
[self drawLine];

-(void)drawLine {
    CGFloat X1 = self.frame.size.width/2-100;
    CGFloat Y1 = 260;
    CGFloat X2 = self.frame.size.width/2+100.0;
    CGFloat Y2 = 260;

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(X1, Y1)];
    [path addLineToPoint:CGPointMake(X2, Y2)];

    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = [path CGPath];
    shapeLayer.strokeColor = [[UIColor blueColor] CGColor];
    shapeLayer.lineWidth = 1.5;
    shapeLayer.fillColor = [[UIColor redColor] CGColor];
    shapeLayer.strokeEnd =0;

    [self.layer addSublayer:shapeLayer];
    [self performSelector:@selector(startTotalLine) withObject:nil afterDelay:1.5];
}

- (void)startTotalLine {   
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.duration = 3.5f;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [animation setAutoreverses:NO];
    [animation setFromValue:[NSNumber numberWithInt:0]];
    [animation setToValue:[NSNumber numberWithInt:1]];
    [shapeLayer addAnimation:animation forKey:@"animatePath"];
}

默认的“strokeEnd”值为1,因此在开始时将其设置为0(没有线条出现)。顺便提一下,这里提供了有用的示例:http://jamesonquave.com/blog/fun-with-cashapelayer/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接