2015-07-22 2 views
-1

Я хотел бы создать анимацию, похожую на прокрутку в меню iPhone. Это означает, что если вы достаточно проведите пальцем, анимация приведет вас к новой странице, но если вы проведете только небольшую анимацию, вы вернетесь на стартовую страницу после того, как закончите салфетку.Core Animation speed

До сих пор я красть распознаватель, который прослушивает положение пальца на экране и следует за движением пальца. Анимация смотрит на конец жестов, если палец перемещается более чем на 1/3 ширины экрана и решает, следует ли перейти к концу или вернуться к началу.

- (void)panGestureHandler:(UIPanGestureRecognizer*)recognizer 
{ 
    if (recognizer.state == UIGestureRecognizerStateEnded) 
    { 
     //if our gesture was enough to let animation roll to its end 
     if (fabsf(translation.x) > CGRectGetWidth(self.view.frame) * 0.33) 
     { 
      [self finishLayer:categoryControllerMain.view.layer animation:menuOpenSwipeAnimateMoveLeft withForward:NO]; 
     } 
     //finger movement was below .33% of screen width so animate to initial state 
     else 
     { 
      [self finishLayer:categoryControllerMain.view.layer animation:menuOpenSwipeAnimateMoveLeft withForward:NO]; 

     } 
    } 
    else if (recognizer.state == UIGestureRecognizerStateChanged) 
    { 
     //We put layer speed to zero so we can control animation with timeoffset in relation to finger pan movement 
     categoryControllerMain.view.layer.speed = 0.0; 
     [categoryControllerMain.view.layer addAnimation:menuOpenSwipeAnimateMoveLeft forKey:@"menuOpenMoveLeft"]; 
     categoryControllerMain.view.layer.timeOffset = fabs(translation.x/CGRectGetWidth(self.view.frame)); 
    } 
} 

И это метод, который говорит анимации, следует ли двигаться к ее концу или началу, в соответствии с движением пальца. Если я просто немного поскользнулся, анимация продолжается с speed = -1;, т. Е. Она начинает идти назад, но когда она доходит до конца или в этом случае начинается, все слои просто исчезают. Здесь не относится к presentationLayer, потому что когда анимация заканчивается, все слои должны быть в этой точной точке, потому что это их исходная точка. Вместо этого все слои исчезают, и когда я пытаюсь снова прокрутить, они появляются в правильных местах.

- (void)finishLayer:(CALayer*)layer animation:(CAKeyframeAnimation*)animation withForward:(BOOL)shouldGoForward 
{ 

    pan.enabled = NO; 
    if (shouldGoForward) 
    { 
     //animation continues 
     CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; 
     layer.timeOffset = 0.0; 
     layer.beginTime = 0.0; 
     CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; 
     layer.beginTime = timeSincePause; 
     layer.speed = 1.0; 
    } 
    else 
    { 
     //we want to take it back. This is where strange things happen. Perhaps timeoffset is not right 
     layer.timeOffset = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; 
     layer.beginTime = CACurrentMediaTime(); 
     layer.speed = -1; 
    } 
} 

Окончательное рассмотрение: Если мои анимации были линейными, то я мог бы создать другую анимацию для каждой анимации с самого начала, вычислить, где начать и сделать его в качестве одной анимации. Но у моих анимаций есть CAMediaTimingFunction s, которые не позволяют мне рассчитать точное положение в противоположной анимации.

EDIT

Вопрос заключается в следующем: как выполнить основную анимацию с speed = -1 так, что когда анимация катится назад, все слои/виды остаются видимыми на экране?

Заранее спасибо

+0

В чем вопрос? – Caleb

+0

@Caleb Я отредактировал мое сообщение. –

ответ

1

OK, если кто-нибудь должен решить подобный вопрос, вот сделка.

Вы не должны использовать тот же объект анимации. Правильный ответ - установить speed = -1.0, но не на ту анимацию, которую вы использовали ранее. Вместо этого создайте новую анимацию со всеми одинаковыми значениями, кроме speed, которая должна быть установлена ​​в -1. В этом случае у вас есть совершенно новая анимация, которая не будет иметь проблем, вызванных изменением speed.

только вы должны быть осторожны, чтобы установить repeatDuration хотя. Вы устанавливаете свойство timeOffset, но если вы оставите продолжительность до того же значения, что и исходная анимация, она дойдет до конца и начнется. Таким образом, способ сократить свою длину - установить значение repeatDuration на точное значение как timeOffset. Итак, теперь он останавливается на последнем кадре оригинальной анимации, и все работает так, как ожидалось.

Как упоминалось ранее, использование такой же анимации не было возможным, потому что, когда анимация достигла своего конца (или мы могли бы сказать начало), layer исчезнет.

Правши, вот код, который возвращает в исходное состояние по тому же свойству исходной анимации.

CGFloat elapsedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; 
layer.speed = 1; 

CAKeyframeAnimation* animationBackwards = [animation copy]; 
animationBackwards.speed = -1.0; 
animationBackwards.timeOffset = elapsedTime; 
animationBackwards.repeatDuration = elapsedTime; 
[layer removeAnimationForKey:animationName]; 
[layer addAnimation:animationBackwards forKey:animationName]; 
Смежные вопросы