【问题标题】:iPhone Core Animation - Drawing a CircleiPhone 核心动画 - 画一个圆
【发布时间】:2011-11-03 06:37:36
【问题描述】:

我想制作一个动画。我能解释这一点的最好方法是,如果你能想象画一个圆圈。它从顶部或 12 点开始,一直沿顺时针方向绘制,直到在 10 秒左右的空间内变成一个完整的圆圈。

我来到这里的壁橱是使用Core Animation(使用示例代码here)绘制一个围绕中心点旋转的点。但是我不知道如何画圆圈?非常欢迎任何建议。

非常感谢:)

【问题讨论】:

  • 您是要绘制一个角度增加的圆形扇区,直到它变成一个完整的圆(填充),还是只绘制一条曲线直到它变成一个完整的圆(只是轮廓,未填充)?
  • @DavidRönnqvist 我试图画一条曲线直到它变成一个完整的圆,只是轮廓没有填充:)

标签: iphone core-animation


【解决方案1】:

您真正应该做的是为 CAShapeLayer 的笔划设置动画,其中路径是一个圆。这将使用 Core Animation 加速,并且比在 -drawRect: 中绘制圆的一部分更容易。

下面的代码将在屏幕中心创建一个圆形图层,并按顺时针方向对其笔划进行动画处理,使其看起来好像正在绘制。你当然可以使用任何你喜欢的形状。 (您可以阅读 Ole Begemanns 博客上的 this article 了解更多关于如何为形状图层的笔划设置动画的信息。)

注意: stoke 属性与图层上的边框属性不同。要更改笔画的宽度,您应该使用“lineWidth”而不是“borderWitdh”等。

// Set up the shape of the circle
int radius = 100;
CAShapeLayer *circle = [CAShapeLayer layer];
// Make a circular shape
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) 
                                         cornerRadius:radius].CGPath;
// Center the shape in self.view
circle.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius, 
                              CGRectGetMidY(self.view.frame)-radius);

// Configure the apperence of the circle
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor blackColor].CGColor;
circle.lineWidth = 5;

// Add to parent layer
[self.view.layer addSublayer:circle];

// Configure animation
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
drawAnimation.duration            = 10.0; // "animate over 10 seconds or so.."
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];

// Experiment with timing to get the appearence to look the way you want
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

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

【讨论】:

  • 感谢 David 为代码带来的巨大和平!我有一个问题:你如何动画填充整个圆圈,而不仅仅是曲线? (你在评论他的问题时问 bennythemink 的第一件事)
  • 还有其他方法。您可以创建一个自定义图层并为其设置动画。看看this great tutorial for animating pie slices with a custom CALayer
  • 您必须在单独的图层中绘制完整的渐变,并使用动画圆圈作为蒙版。当您为圆形蒙版的填充设置动画时,渐变将变得可见。
  • @CyrilMestrom 是的,所有动画都是这样。一旦动画完成,它们就会回到“真实”值。您还必须在图层上将strokeEnd 属性设置为0.5。本例中没有这样做,因为 1.0 是默认值。
  • 我将代码更改为使用bezierPathWithArcCenter 而不是bezierPathWithRoundedRect,因为我更喜欢它提供给我的坐标系,以及向相反方向设置动画的能力......但这保存了我很多时间非常感谢! :)
【解决方案2】:

根据@David 的回答,这是该问题的另一种解决方案。这种方法可以让您设置圆圈动画的方向,并提供更多控制。 编辑:我已经在how to draw a circle with Swift 上写了一篇博文,我会尽量跟上测试版的最新情况。如果下面的代码不适合您,请检查那里。

let radius = 100.0

// Create the circle layer
var circle = CAShapeLayer()

// Set the center of the circle to be the center of the view
let center = CGPointMake(CGRectGetMidX(self.frame) - radius, CGRectGetMidY(self.frame) - radius)

let fractionOfCircle = 3.0 / 4.0

let twoPi = 2.0 * Double(M_PI)
// The starting angle is given by the fraction of the circle that the point is at, divided by 2 * Pi and less
// We subtract M_PI_2 to rotate the circle 90 degrees to make it more intuitive (i.e. like a clock face with zero at the top, 1/4 at RHS, 1/2 at bottom, etc.)
let startAngle = Double(fractionOfCircle) / Double(twoPi) - Double(M_PI_2)
let endAngle = 0.0 - Double(M_PI_2)
let clockwise: Bool = true

// `clockwise` tells the circle whether to animate in a clockwise or anti clockwise direction
circle.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: clockwise).CGPath

// Configure the circle
circle.fillColor = UIColor.blackColor().CGColor
circle.strokeColor = UIColor.redColor().CGColor
circle.lineWidth = 5

// When it gets to the end of its animation, leave it at 0% stroke filled
circle.strokeEnd = 0.0

// Add the circle to the parent layer
self.layer.addSublayer(circle)

// Configure the animation
var drawAnimation = CABasicAnimation(keyPath: "strokeEnd")
drawAnimation.repeatCount = 1.0

// Animate from the full stroke being drawn to none of the stroke being drawn
drawAnimation.fromValue = NSNumber(double: fractionOfCircle)
drawAnimation.toValue = NSNumber(float: 0.0)

drawAnimation.duration = 30.0

drawAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)

// Add the animation to the circle
circle.addAnimation(drawAnimation, forKey: "drawCircleAnimation")

【讨论】:

    【解决方案3】:

    我找到了解决这个问题的方法,代码如下。我对手头问题的解释似乎搞砸了,所以将其重写为另一个问题,得到了正确的解决方案,请参阅here

    感谢大家的建议!

    -(void)drawRect:(CGRect)rect
    {
        // Drawing code
    
        CGRect allRect = self.bounds;
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        // Draw background
        CGContextSetRGBStrokeColor(context, self.strokeValueRed, self.strokeValueGreen, self.strokeValueBlue, self.strokeValueAlpha); // white
        CGContextSetLineWidth(context, 5);
    
        // Draw progress
        CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2);
        CGFloat radius = (allRect.size.width - 4) / 2;
        CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees
        CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle;
        CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
        CGContextStrokePath(context);
    }
    

    【讨论】:

      【解决方案4】:

      好的,我有部分修复。我找到了以下绘制圆段的代码。它基本上是一个 UIView 子类,每次更新进度时都会触发它的 drawRect。我现在唯一的问题是如何更改它,而不是绘制部分或切片,而只是绘制圆形笔划?

      -(void)drawRect:(CGRect)rect 
      {
          // Drawing code
      
          CGRect allRect = self.bounds;
          CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f);
      
          CGContextRef context = UIGraphicsGetCurrentContext();
      
          // Draw background
          CGContextSetRGBStrokeColor(context, self.strokeValueRed, self.strokeValueGreen, self.strokeValueBlue, self.strokeValueAlpha); // white
          CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 0.1f); // translucent white
          CGContextSetLineWidth(context, self.lineWidth);
          CGContextFillEllipseInRect(context, circleRect);
          CGContextStrokeEllipseInRect(context, circleRect);
      
          // Draw progress
          CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2);
          CGFloat radius = (allRect.size.width - 4) / 2;
          CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees
          CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle;
          CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // white
          CGContextMoveToPoint(context, center.x, center.y);
          CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
          CGContextClosePath(context);
          CGContextFillPath(context);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-08
        相关资源
        最近更新 更多