UIView infinite loop Animation to call a method after every repeat cycle

强颜欢笑 提交于 2019-12-06 15:34:55
Nader Eloshaiker

Got it working perfectly.

Here is what I did:

1/ Applied a CABasicAnimation rotation object to the layer to rotate 360 degrees every 2 sec. (don't need to make it cumulative that way)

2/ Set up a timer to call the presentation layer from the layer every .1 sec.

3/ Calculate the angle from the 3D transform stored in the presentation layer. Click here for my answer on how to do this.

4/ Check for intersecting angles.

Done :-)

Things to watch out for: The 3D transform is based on angles between 180 and -180 degrees and not 0 to 360 degrees Use atan2 and not atan as the later will only give angles in the first quadrant.

OK, I have come a long way since I posted this question.

The accepted design pattern is to actually generate a clock tick (commonly using CADisplayLink) that runs at either 30 frames per second or 60 depending on how smooth and fast you want the animation to be. At every frame callback, you modify the transform on the view/layer and use a transaction to display it.

Some key notes: Build a method to test for intersecting line and point:

-(BOOL)intersectWithAngle:(CGFloat)rad {        
    return (rad <= angle && rad >= angle - angleIncrement);
}

You must use transactions when attempting to modify a property that is animatable to prevent the layer/view from animating the new value itself. (You don't want to animate it twice)

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

self.transform = rotationTransform;

[CATransaction commit];

No need to keep creating new transforms every frame, this is just wasteful and consumes resources. Best create an instance variable / property called rotationTransform and modify that every frame and re-apply it to the layer/view.

-(void)displayFrame {   
    rotationTransform.a = cos(angle);
    rotationTransform.b = sin(angle);
    rotationTransform.c = -sin(angle);
    rotationTransform.d = cos(angle);

    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

    self.transform = rotationTransform;

    [CATransaction commit];
}

Next, create a method to actually set up the angle, use an instance variable / property to store the angle and define your angle incrementation (I use 3 degrees), also predefine 2-pi so that you are not always recalculating it.

-(void)processFrame {
    angle += angleIncrement;
    if (angle >= M_2PI) {
        angle -= M_2PI;
    }

    if ([self intersectWithAngle:point.angle]) {
        [point animate];
    } 
}

Finally, build your method that is called by CADisplayLink which sets up the frame and displays it while maintaining frame sync.

-(void)displayLinkDidTick {
    // get the time now
    NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate];

    if (timeOfLastDraw == 0) {
        numberOfTicks = 1;
    } else {
        NSTimeInterval timeSinceLastDraw = timeNow - timeOfLastDraw;
        NSTimeInterval desiredTimeInterval = kFrameDuration;

        numberOfTicks = (NSUInteger)(timeSinceLastDraw / desiredTimeInterval);      
    }

    if (numberOfTicks > 4) {
        numberOfTicks = 4;
        timeOfLastDraw = timeNow;
    } else {
        timeOfLastDraw += numberOfTicks * kFrameDuration;
    }


    while(numberOfTicks--) {

        [self processFrame];
        if (spriteState == SpriteStateIdle)
            break;
        }

    [self displayFrame];

}

This code extract has been heavily modified for this post, in actually fact I do the animation of the scan line and the blipping of the point in the same CADisplayLink instance.

I wonder if this would work:

UIView* yourView = ...;
// preparing the callbacks:
void(^)(void) animations = ...; // the animation would rotate 10 degrees
void(^)(BOOL) completion = ^(BOOL finished) {
  // do your radar stuff
  [UIView animateWithDuration:0.1 animations:animations completion:completion];
}

// the first call to start it all
[UIView animateWithDuration:0.1 animations:animations completion:completion];

The idea is to call the animation sequence again each time after finishing your radar activity, assuming the radar check is not a heavy one it should be smooth.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!