2015-03-14 2 views
1

Как изменить направление и начальную позицию CALayer анимация?Как изменить направление анимации CALayer

Например, если анимировать форму круга, используя следующий код:

-(void)drawCircle { 
    CAShapeLayer *circleShapeLayer = [[CAShapeLayer alloc] init]; 
    circleShapeLayer.path   = [self circleBezierPath].CGPath; 
    circleShapeLayer.strokeColor = [UIColor lightGrayColor].CGColor; 
    circleShapeLayer.fillColor  = [UIColor clearColor].CGColor; 
    circleShapeLayer.lineWidth  = 2; 
    [self.view.layer addSublayer:circleShapeLayer]; 

    CABasicAnimation *circleShapeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 
    circleShapeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
    circleShapeAnimation.duration   = 1.0f; 
    circleShapeAnimation.fromValue   = @(0.0f); 
    circleShapeAnimation.toValue   = @(1.0f); 
    [circleShapeLayer addAnimation:circleShapeAnimation forKey:@"strokeEnd"]; 
} 

-(UIBezierPath *)circleBezierPath { 
    UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 100, 100)]; 
    return circlePath; 
} 

Анимация всегда начинается в 3 часа и анимируется в направлении по часовой стрелке.

Как заставить его начать в 12 часов (или в любом другом положении) и анимировать в против часовой стрелки?

+0

изменить путь. Ваш путь начинается с этой точки и продолжается в этом направлении. –

+0

Что это значит?Путь безье начинается с (x, y) = (100 100), что определенно не является местом начала анимации. Есть ли способ указать начальную точку анимации и ее направление? – Digitech

ответ

6

Что происходит

При создании овал в прямоугольнике (эфир с использованием UIBezierPath функций CGPath) создает овал или эллипс, который соответствует указанному прямоугольник. Это означает, что центр овала не то же самое, как происхождение прямоугольника:

An oval in a rectangle

Анимация всегда начинается в 3 часа и проходит против часовой стрелки, потому что это путь электрической дуги, что является круг от 0 до 2л в системе координат по умолчанию:

Angles in the default coordinate system

Это означает, что путь вы оживляющий ход действительно выглядит следующим образом:

enter image description here

неправильный способ решить проблему

Глядя на пути, вы можете переместить начальную точку, вращая вид. Это не рекомендуется, потому что он имеет побочные эффекты. Если есть какие-либо подслои, они также будут повернуты. Направление хода может быть изменено либо переворачиванием вида (масштабирование отрицательным вдоль одной оси), либо путем оживления начала хода от 1 до 0, а не окончания хода.

Все решения этих тезисов будут работать, но имеют побочные эффекты и менее понятны, что предпочтительнее.

Лучшее решение

Мне нравится смотреть на эту проблему, как это: код анимации делает правильно, оживляющий удар от нуля до всего этого, но начальная точка и погладить направление пути это не то, что ожидается. Это означает, что «проблема» лежит на пути.

Вместо того, чтобы использовать bezierPathWithOvalInRect:, вы можете создать свой собственный полный круг, используя дугу, проходящую от любого начального угла до любого конечного угла по часовой стрелке или против часовой стрелки. Все, что требуется, это то, что вы вычисляете центр круга (и начальный и конечный углы). Посмотрев на систему координат по умолчанию, мы видим, что начальный угол равен 3π/2 или -π/2. Конечный угол затем плюс или минус 2π от начального угла (в зависимости от того, по часовой стрелке или против часовой стрелки).

Создание дуги, как это может выглядеть примерно так:

- (UIBezierPath *)circleBezierPath 
{ 
    CGRect boundingRect = CGRectMake(100, 100, 100, 100); 
    CGPoint center  = CGPointMake(CGRectGetMidX(boundingRect), CGRectGetMidY(boundingRect)); 
    CGFloat radius  = MIN(CGRectGetWidth(boundingRect), CGRectGetHeight(boundingRect)); 

    CGFloat twelveOClockAngle = -M_PI_2; 
    BOOL clockwise = NO; // NO for counter clockwise 

    CGFloat startAngle = twelveOClockAngle; 
    CGFloat endAngle = startAngle + (2.0*M_PI * (clockwise ? 1.0 : -1.0)); 

    return [UIBezierPath bezierPathWithArcCenter:center 
              radius:radius 
             startAngle:startAngle 
             endAngle:endAngle 
             clockwise:clockwise]; 
} 
+0

Это имеет смысл, спасибо за подробное объяснение! – Digitech

+0

@ Digitech Я рад, что вы нашли ответ полезным. Если он решает вашу проблему, подумайте над тем, чтобы принять его принятый ответ. Комментарии, как правило, запрашивают разъяснения, оставляют конструктивную критику или добавляют важную, но небольшую дополнительную информацию, а не для общения (например, «спасибо»). Для получения дополнительной информации см. [Помощь> Запрашивать> Что делать, если кто-то отвечает на мой вопрос?] (Http://stackoverflow.com/help/someone-answers) –

+0

Радиус должен быть шириной или высотой/2 – gbhall