Objective-C中的“推”animation

我有两个视图:A和B.A位于屏幕的顶部,B位于屏幕的底部。

当用户按下一个button时,视图B用EaseInEaseOut贝塞尔曲线向上animation,直到达到y = 0。当B正在到达目的地的途中,当它碰到A时,它应该将A向上。换句话说,当B在从底部到顶部的过渡期间传递了一个y坐标(A的y原点+高度),A应该坚持B,所以看起来B向上推A。

我到目前为止所尝试的:

  • 在用户按下button后立即将目标+select器注册到CADisplayLink。 在这个select器中,通过访问其presentationLayer并相应地调整A的y坐标来请求视图B的y坐标。 然而,这种方法不够准确:presentationLayer的框架落在B屏幕上的当前位置(这可能是因为-presentationLayer在当前时间重新计算animation视图的位置,这需要比1帧更长的时间) 。 当我增加B的animation持续时间,这种方法工作正常。
  • 在用户按下button后立即将目标+select器注册到CADisplayLink。 在这个select器内部,通过求解x =经过时间/animation持续时间(应该返回行距/总距离的商距)的贝塞尔方程来计算B的当前y坐标。 我使用苹果的开源UnitBezier.h( http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h )。 但是,结果是不正确的。

任何build议,我可以尝试下一个?

你说你试过“有生命的B,用显示链接更新A”的技术,结果是“A”落后于“B”。 从理论上讲,你可以创build一个新的视图“C”,然后在显示链接中相应地调整B和A的帧,消除任何延迟(相对于彼此)。

两个简单的scheme:

  1. 仅使用animationWithDuration :您可以将animation分成两个嵌套的animation,使用“缓入”animation将“B”移动到“A”,然后使用“缓出”来animation移动“B”和“一个“的其余部分。 唯一的技巧就是确保两个duration值是合理的,这样animation的速度看起来不会改变。

     CGFloat animationDuration = 0.5; CGFloat firstPortionDistance = self.b.frame.origin.y - (self.a.frame.origin.y + self.a.frame.size.height); CGFloat secondPortionDistance = self.a.frame.size.height; CGFloat firstPortionDuration = animationDuration * firstPortionDistance / (firstPortionDistance + secondPortionDistance); CGFloat secondPortionDuration = animationDuration * secondPortionDistance / (firstPortionDistance + secondPortionDistance); [UIView animateWithDuration:firstPortionDuration delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{ CGRect frame = self.b.frame; frame.origin.y -= firstPortionDistance; self.b.frame = frame; } completion:^(BOOL finished) { [UIView animateWithDuration:secondPortionDuration delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ CGRect frame = self.b.frame; frame.origin.y -= secondPortionDistance; self.b.frame = frame; frame = self.a.frame; frame.origin.y -= secondPortionDistance; self.a.frame = frame; } completion:nil]; }]; 
  2. 您可以让animateWithDuration处理完整的“B”animation,但是随后使用CADisplayLink并使用presentationLayer来检索B的当前frame并相应地调整A的帧:

     [self startDisplayLink]; [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ CGRect frame = self.b.frame; frame.origin.y = self.a.frame.origin.y; self.b.frame = frame; } completion:^(BOOL finished) { [self stopDisplayLink]; }]; 

    其中启动,停止和处理显示链接的方法定义如下:

     - (void)startDisplayLink { self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)]; [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; } - (void)stopDisplayLink { [self.displayLink invalidate]; self.displayLink = nil; } - (void)handleDisplayLink:(CADisplayLink *)displayLink { CALayer *presentationLayer = self.b.layer.presentationLayer; if (presentationLayer.frame.origin.y < (self.a.frame.origin.y + self.a.frame.size.height)) { CGRect frame = self.a.frame; frame.origin.y = presentationLayer.frame.origin.y - self.a.frame.size.height; self.a.frame = frame; } } 

你可以尝试followal algorythm:

1)把A和B放在UIView(即UIview * gropedView)

2)改变直到等于A.y + A.height(所以B在A下是正确的)

3)animation分组视图