简体   繁体   English

iPhone:核心动画:触及视图边界后反转动画

[英]iphone: Core Animation: Reversing animation after hitting view boundary

I am trying hands at Core Animation on iphone. 我正在尝试在iPhone上使用Core Animation。

Details of what I have done so far: I am using layers and CAKeyFrameAnimation using path. 到目前为止,我已完成的操作的详细信息:我正在使用图层,并使用path使用CAKeyFrameAnimation。 I have created a layer with Contents set to a bitmap file of a fly which I want to animate on a spiral path. 我创建了一个内容层设置为蝇状位图文件的图层,该图层要在​​螺旋路径上进行动画处理。 The centre point of the spiral path is at CGPoint (150,150). 螺旋路径的中心点位于CGPoint(150,150)。 The end point of the spiral path is a radius of 100.0f. 螺旋路径的终点半径为100.0f。

What I want to achieve: I further want to increase the radius to a value so that the spiral can go beyond the bounds of the view frame, but when it reaches the bound, I desire the fly to trace back the path. 我想要实现的目标:我还想将半径增加到一个值,以使螺旋线可以超出视框的边界,但是当螺旋线到达边界时,我希望苍蝇回溯路径。

EDIT: (adding code): 编辑:(添加代码):

-(IBAction) clickToAnimate:(id) sender 
{ 
    //create a path to animate the fly 
    CGFloat minRadius = 5.0f; 
    CGFloat maxRadius = 100.0f; 
    CGFloat radiusOffset = 5.0f; 
    float i; 
    int count =1; 
    int remainder; 
    curvePath = CGPathCreateMutable(); 
    //this looping mimics the "spiral path" 
    for (i = minRadius; i <= maxRadius; i = i + 5.0f) 
    { 
        remainder = count % 2; 
        if (remainder == 0) 
        { 
            CGPathAddArc(curvePath, NULL, currentPoint.x, currentPoint.y, i, M_PI / 2, 1.5 * M_PI, NO);  
        } 
        else 
        {
        CGPathAddArc(curvePath, NULL, currentPoint.x, currentPoint.y + radiusOffset, i, 1.5 * M_PI , M_PI / 2, NO);     
    }

            count = count +1; 
   }
    //add timer
    timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(checkCoordinatesOnTimer) userInfo:self repeats:YES];

        CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; 
        animation.calculationMode = kCAAnimationPaced; 
        animation.path = curvePath; 
        animation.duration = 25.0f; 
        animation.autoreverses = YES; 
        animation.fillMode = kCAFillModeFrozen; 
        CGPathRelease(curvePath); 
        [animationLayer addAnimation:animation forKey:@"position"]; 

}

Approach taken: I set up a timer, which would check the co-ordinates of the animation layer every half second. 采取的方法:我设置了一个计时器,它将每半秒检查一次动画层的坐标。 The co-ordinates would be checked against the bounding x and y co-ordinates. 将对照边界x和y坐标检查坐标。 If the co-ordinates are found to cross the boundary, we will disable the timer and start with the reverse animation process. 如果发现坐标越过边界,我们将禁用计时器并从反向动画处理开始。 The reverse animation process would first check the angle from horizontal at which the animation is when it crosses the boundary. 反向动画处理将首先检查动画越过边界时与水平线之间的角度。 Using this angle and radius from center point, create a path for reverse animation. 使用距中心点的角度和半径,创建用于反向动画的路径。 Details can be found in code below. 可以在下面的代码中找到详细信息。

- (void) checkCoordinatesOnTimer
  {

     if (!presentLayer) 
     {
         presentLayer =[[CALayer alloc] init];
     }
     presentLayer = [animationLayer presentationLayer];

     CGPoint curPt;
     curPt.x = presentLayer.position.x;
     curPt.y = presentLayer.position.y;

     currRadius = sqrt(pow(fabsf(curPt.x - centerPoint.x), 2) + pow(fabsf(curPt.y -     centerPoint.y), 2));
     if ((curPt.x >= CGRectGetMaxX(self.view.frame)) || (curPt.y >= CGRectGetMaxY(self.view.frame))) 
     {
         [timer invalidate];
         [self reverseAnimation:curPt];
     }


 }

-(void) reverseAnimation:(CGPoint)curPoint 
{
    CGFloat angle = (CGFloat)[self calculateAngleInRadians:curPoint];

    maxRadius = currRadius;
    float i;
    int count =1;
    int remainder;
    BOOL firstLap = YES;

    CGPathRelease(curvePath);
    curvePath =  CGPathCreateMutable();
    for (i = maxRadius; i >= minRadius; i = i - 5.0f) 
    {
        remainder = count % 2 ;
        if (firstLap) 
        {
            if ((angle >= (M_PI/2)) && (angle <= 1.5 *M_PI)) 
                     //2nd and third quard, 
             //angle to change from final angle to 90
            {
                 CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, angle, 1.5 * M_PI, FALSE);
            }
            else 
            { 
                CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, angle,  M_PI / 2 , FALSE);       
            }
            firstLap = NO;
            continue;
      }
      else 
      {
            if (remainder == 0)
            {
                CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, 1.5* M_PI,  M_PI / 2, FALSE);    
            }
            else 
            {

                CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y + radiusOffset, i, M_PI / 2 ,1.5* M_PI, FALSE);      
            }
       }
       count = count +1;
    }

    animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animation.calculationMode =kCAAnimationPaced; // for even pacing of animation in segments.
    animation.path = curvePath;
    animation.duration = 40.0f;
    animation.fillMode = kCAFillModeForwards;
    CGPathRelease(curvePath);
    [animationLayer addAnimation:animation forKey:@"position"];
}
-(CGFloat) calculateAngleInRadians:(CGPoint) pt
{

CGFloat xLen = fabsf(centerPoint.x - pt.x);
CGFloat yLen = fabsf(centerPoint.y - pt.y);
double value = yLen/xLen;

double angle = atan(value);
double angleInDeg = ( 180 * angle/ M_PI);
double finalAngle;
if ((pt.x > centerPoint.x) || (pt.y > centerPoint.y)) {
    finalAngle = angle;
}
else if ((centerPoint.x > pt.x) || (pt.y > centerPoint.y))
{
    finalAngle = M_PI/2 + angle;
}
else if ((centerPoint.x > pt.x) || (centerPoint.y > pt.y))
{
    finalAngle = M_PI + angle;
}
else {
    finalAngle = (1.5 * M_PI) + angle;
}
return finalAngle;
}

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

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