“推”的动画在Objective-C(“Push” animation in Objective-C

2019-08-17 12:54发布

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

当用户按下按钮时,图B,其中A EaseInEaseOut Bezier曲线向上动画直到它到达Y = 0。当B是在它的途中到它的目的地,它应该推起来,当它击中A.换句话说,当B具有从底部到顶部的过渡期间,通过一定的y坐标(A的y原点+高),A应该坚持到B如此看来乙推送向上。

我迄今为止尝试:

  • 注册一个目标+选择到CADisplayLink后,立即在用户按下按钮。 内部此选择,请求视图乙的Y通过访问其表示层坐标和调整的Y坐标相应。 然而,这种方法被证明是不够准确的:在表示层的帧后面是在屏幕上B的当前位置(这可能是因为-presentationLayer重新计算当前时间的动画视图的位置,其时间比1帧) 。 当我增加B的动画时间,这种方法效果很好。
  • 注册一个目标+选择到CADisplayLink后,立即在用户按下按钮。 这里面选择器,计算B的当前y通过求解贝塞尔方程对于x =经过时间/持续时间的动画(其应返回的商行进距离/总距离)坐标。 我用苹果的开源UnitBezier.h这个( http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h )。 然而,结果是不正确的。

什么我可以尝试下有什么建议?

Answer 1:

你说,你尝试过的“动画B和使用显示器链接更新”技术,它导致了“A”落后“B”。 理论上可以动画一个新的视图,“C”,然后在显示的链接,这将消除任何滞后(相对于彼此)相应地调整B和A的帧。



Answer 2:

两个简单的解决方案:

  1. 使用animationWithDuration只有:你可以把你的动画到两个嵌套的动画,使用“缓解”动画“B”的运动达人“A”,然后使用“缓出”动画“B”和“运动A”的方式休息。 这里唯一的问题是,以确保这两个duration值是有意义的,这样的动画速度不会出现改变。

     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”的完整动画,但后来使用CADisplayLink和使用presentationLayer来检索B的当前frame ,并相应地调整的框架:

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


Answer 3:

您可以尝试跟随着algorythm:

1)把A和B中的UIView(即的UIView * gropedView)

2)改变由直到它将等于A.y + A.height(因此B将向右下的A)

3)动画groupedView



文章来源: “Push” animation in Objective-C