Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone &引用;推;Objective-C中的动画_Iphone_Ios_Objective C_Core Animation - Fatal编程技术网

Iphone &引用;推;Objective-C中的动画

Iphone &引用;推;Objective-C中的动画,iphone,ios,objective-c,core-animation,Iphone,Ios,Objective C,Core Animation,我有两个视图:A和B。A位于屏幕顶部,B位于屏幕底部 当用户按下按钮时,视图B将使用EaseInEaseOut bezier曲线向上设置动画,直到其达到y=0。当B在它到达目的地的途中,当它碰到A时,它应该向上推A。换句话说,当B在从底部到顶部的过渡过程中通过某个y坐标(A的y原点+高度)时,A应该粘在B上,所以B似乎向上推A 到目前为止,我所尝试的: 用户按下按钮后,立即将target+选择器注册到CADisplayLink。在该选择器中,通过访问视图B的presentationLayer请

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

当用户按下按钮时,视图B将使用EaseInEaseOut bezier曲线向上设置动画,直到其达到y=0。当B在它到达目的地的途中,当它碰到A时,它应该向上推A。换句话说,当B在从底部到顶部的过渡过程中通过某个y坐标(A的y原点+高度)时,A应该粘在B上,所以B似乎向上推A

到目前为止,我所尝试的:

  • 用户按下按钮后,立即将target+选择器注册到CADisplayLink。在该选择器中,通过访问视图B的presentationLayer请求视图B的y坐标,并相应地调整A的y坐标。但是,这种方法不够精确:presentationLayer的帧在屏幕上B的当前位置后面(这可能是因为-presentationLayer在当前时间重新计算动画视图的位置,这需要超过1帧)。当我增加B的动画持续时间时,此方法效果良好
  • 用户按下按钮后,立即将target+选择器注册到CADisplayLink。在该选择器内,通过求解bezier方程,计算B的当前y坐标,该方程的x=经过的时间/动画持续时间(应返回所行驶的距离/总距离的商)。为此,我使用了苹果的开源UnitBezier.h()。然而,结果并不正确
有没有关于我下一步可以尝试的建议?

两个简单的解决方案:

  • 仅使用
    animationWithDuration
    :您可以将动画分解为两个嵌套动画,使用“ease-in”设置“B”向“A”移动的动画,然后使用“ease-out”设置“B”和“A”向上移动的动画。这里唯一的技巧是确保这两个
    持续时间
    值有意义,以便动画的速度看起来不会改变

    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];
                     }];
    
  • 您可以让
    animateWithDuration
    处理“B”的完整动画,但随后使用
    CADisplayLink
    presentationLayer
    检索B的当前
    ,并相应地调整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;
        }
    }
    
    -(无效)开始显示链接
    {
    self.displayLink=[CADisplayLink displayLinkWithTarget:self-selector:@selector(handleDisplayLink:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop]forMode:NSDefaultRunLoopMode];
    }
    -(无效)停止显示链接
    {
    [self.displayLink失效];
    self.displayLink=nil;
    }
    -(无效)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=自我分析框架;
    frame.origin.y=presentationLayer.frame.origin.y-self.a.frame.size.height;
    self.a.frame=框架;
    }
    }
    

  • 您说您尝试了“设置B动画并使用显示链接更新A”技术,结果“A”落后于“B”。从理论上讲,您可以设置新视图“C”的动画,然后在显示链接中相应地调整B和a的帧,这将消除任何延迟(相对于彼此)。

    您可以尝试以下算法:

    1) 将A和B放入UIView(即UIView*gropedView)

    2) 改变B.y,直到它等于A.y+A.height(因此B将位于A的正下方)


    3) 动画组视图

    在类似的情况下,我采用了一种方法,即两个视图都在整个距离内设置动画,但使用一个带有时间偏移和a动画开始时间的CAAnimationGroup,以防止在B点击它之前实际显示它。(请参阅)您的解决方案听起来更简单。绝妙而简单的解决方案。谢谢