简体   繁体   English

核心动画速度

[英]Core Animation speed

I'd like to create animation similar to swiping in menus of iPhone. 我想创建类似于在iPhone菜单中滑动的动画。 That means if you swipe enough, animation takes you to new page, but if you swipe just a little animation takes you back on starting page after finishing swipe gesture. 这意味着如果滑动足够,动画将带您进入新页面,但是如果滑动仅一小段动画,您将在完成滑动手势后回到起始页面。

So far, I have swipe recognizer which listens to position of finger on screen and follows the movement of finger. 到目前为止,我有滑动识别器,它可以侦听手指在屏幕上的位置并跟随手指的移动。 Animation looks at the end of gesture whether finger moved more than 1/3 of screen width and decides whether to proceed to its end or go back to beginning. 动画会查看手势的结束,手指是否移动了屏幕宽度的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));
    }
}

And this is the method which says to animation whether to move towards its end or beginning, according to finger amount movement. 这是根据手指移动量对动画说是向动画的结尾还是起点移动的方法。 If I just swiped a bit, animation continues with speed = -1; 如果我稍稍刷一下,动画将以speed = -1;继续speed = -1; , ie it starts going backwards, but when it gets to its end, or in this case beginning, all layers just disappear. ,即开始向后移动,但是当到达终点或在这种情况下开始时,所有图层都消失了。 Here is not the case of presentationLayer , because when animation ends, all the layers should be at that exact point, because that is their initial point. 这不是presentationLayer的情况,因为动画结束时,所有图层都应在该确切点上,因为那是它们的初始点。 Instead, all the layers are gone, and when I try to swipe again, they appear on their correct locations. 相反,所有图层都消失了,当我尝试再次滑动时,它们会显示在正确的位置。

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

A final consideration: If my animations were linear, then I could create another animation for every animation from beginning, calculate where to start and make it appear as one animation. 最后要考虑的是:如果我的动画是线性的,那么我可以从头开始为每个动画创建另一个动画,计算从哪里开始并使它显示为一个动画。 But my animations have CAMediaTimingFunction s which don't allow me to calculate exact position in opposite animation. 但是我的动画具有CAMediaTimingFunction ,不允许我计算相对动画中的确切位置。

EDIT 编辑

The question is the following: how to perform core animation with speed = -1 so that when animations rolls backwards, all of layers/views stay visible on screen? 问题如下:如何以speed = -1执行核心动画,以便当动画向后滚动时,所有层/视图在屏幕上保持可见?

Thanks in advance 提前致谢

OK, if anyone ever needs to solve similar issue, here is the deal. 好的,如果有人需要解决类似的问题,这就是解决方案。

You shouldn't use same animation object. 您不应该使用相同的动画对象。 The correct answer is to set speed = -1.0 , but not on that animation you'd been using previously. 正确的答案是将speed = -1.0设置speed = -1.0 ,而不是在您以前使用的动画上设置。 Instead, create new animation with all the same values except of speed which should be set to -1. 而是用所有相同的值创建新动画,但speed应设置为-1。 In that case, you a have a brand new animation which is not going to have problems caused by change of speed . 在这种情况下,您将拥有一个全新的动画,该动画不会因speed变化而出现问题。

The only you have to be careful about is to set repeatDuration though. 不过,您唯一需要注意的是设置repeatDuration You set timeOffset property but if you leave duration to the same value as original animation, it will get to its end and start over. 您可以设置timeOffset属性,但是如果将duration设置为与原始动画相同的值,它将结束并重新开始。 So, the way to cut its length is to set the value of repeatDuration to exact value as timeOffset . 因此,缩短长度的方法是将repeatDuration的值设置为timeOffset确切值。 So now it stops at last frame of original animation and everything works as expected. 因此,现在它停止在原始动画的最后一帧,并且一切正常。

As mentioned before, using same animation wasn't an option because when animation reached its end (or we might say beginning), the layer would disappear. 如前所述,使用相同的动画不是一种选择,因为当动画到达终点(或可以说是开始)时,该layer将消失。

Righty, here's the code which takes you back to initial state following the same properties of initial animation. 好的,下面的代码使您按照初始动画的相同属性回到初始状态。

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];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM