IPhone Core Animation - рисование круга

Я хочу создать анимацию. Лучший способ я могу объяснить это, если вы можете вообразить рисование круга. Он начинается в верхней или 12 часов и тянет по часовой стрелке до тех пор, пока он не станет полным кругом в течение 10 секунд.

Шкаф, к которому я пришел, состоит в том, чтобы нарисовать точку, вращающуюся вокруг центральной точки, используя Core Animation (используя пример кода здесь). Но я не понимаю, как нарисовать круг? Любые предложения приветствуются.

Большое спасибо:)

Ответ 1

То, что вам действительно нужно сделать, - это анимировать штрих CAShapeLayer, где путь - это круг. Это будет ускорено с использованием Core Animation и менее беспорядочно, чем рисовать часть круга в -drawRect:.

В приведенном ниже коде будет создан слой формы круга в центре экрана и анимируйте его по часовой стрелке так, чтобы он выглядел так, как будто его рисуют. Вы можете, конечно, использовать любую форму, которую хотите. (Вы можете прочитать этой статьи в блоге Ole Begemanns, чтобы узнать больше о том, как оживить ход слой формы.)

Примечание:, что свойства стоков не совпадают с свойствами границы слоя. Чтобы изменить ширину штриха, вы должны использовать "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"];

Ответ 2

Вот еще одно решение проблемы, основанная на ответе @David. Этот подход позволяет вам установить направление анимации круга и предлагает немного больше контроля. Изменить: Я написал сообщение в блоге как рисовать круг с 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

У меня есть решение этой проблемы, код ниже. Я, кажется, испортил свое объяснение проблемы, поэтому переписал ее как еще один вопрос, на который было получено правильное решение, см. здесь

Спасибо всем за их советы!

-(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, который получает threadRect каждый раз, когда его прогресс должен быть обновлен. Единственный вопрос, который у меня есть сейчас, - это как бы изменить его так, чтобы вместо рисования секций или фрагментов он просто рисовал бы круговой ход?

-(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);
}