UIView无限循环动画在每个重复循环后调用一个方法 [英] UIView infinite loop Animation to call a method after every repeat cycle

查看:113
本文介绍了UIView无限循环动画在每个重复循环后调用一个方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最终试图想出这个范例的设计模式。我在这个网站上没有多少运气但是在这个阶段我会尝试任何东西。

I am at my wits end trying to come up with a design pattern for this paradigm. I haven't had much luck on this site but at this stage I'll try anything.

我正在尝试实现雷达类型的动画,因此我正在旋转查看360度以表示围绕圆圈旋转的半径。我在这个圆圈周围放置了点,并且能够使用标准触发器计算圆心的角度。

I am trying to implement a radar type animation and hence I am rotating a view 360 degrees to represent the radius rotating around the circle. I have placed points around this circle and am able to calculate the angle from the center of the circle using standard trig.

当半径扫过圆圈时,如果它相交有一个点(例如,点的角度等于扫描半径的角度+公差)点闪烁。

As the radius sweeps around the circle, if it intersects with a point (eg angle of the point equals the angle of the sweeping radius + a tolerance) the point flashes on.

现在,我已经接近了这个范例中的一个数字方法,但尚未达到理想的解决方案。这是我尝试过的。

Now, I have approached this paradigm in a number of ways but have not achieved an ideal solution. Here is what I have tried.

第一个:iOS4动画块。我将半径10度旋转,持续时间为.1秒,在完成方法中,检查与点的交点。这里的问题是,如果将选项设置为repeat,则不会调用completion方法。调用完成方法的唯一时间是整个动画终止时,而不是每个重复周期后,所以此解决方案不起作用。

FIRST: iOS4 animation blocks. I would rotated the radius 10 degrees at a time with a duration of .1sec and in the completion method, check for intersections with points. The problem here is that if you set the option to repeat, then the completion method doesn't get called. The only time the completion method gets called is when the entire animation terminates, not after every repeat cycle, so this solution doesn't work.

SECOND:尝试使用显式动画CABasicAnimation。与上面相同的方法,每0.1秒旋转10度并将委托设置为self并实现animationDidFinish方法。在animationDidFinish方法中,我检查了与点的交叉点。我将动画设置为累积,将repeatCound设置为巨大值。 raduis旋转但是再一次,除非我将repeatCount设置为较小的数字,然后只在repeatCount结束时调用,而不是在每个重复循环之后调用,否则不会调用animationDidFinish。

SECOND: Tried explicit animation using CABasicAnimation. Same approach as above, rotating 10 degrees at every .1 seconds and setting the delegate to self and implementing the animationDidFinish method. In the animationDidFinish method, I checked for intersections with point. I set the animation to cumulative and repeatCound to Huge Value. The raduis rotates but once again, the animationDidFinish doesn't get called unless I set the repeatCount to a small number and then it only gets called at the end of the repeatCount, not after every repeat cycle.

第三:使用NSTimer并且这种方法实际上可行,但动画可能会生涩,具体取决于屏幕周围发生的事情。我使用.1秒的计时器刻度并启动10度的单个动画以及每个刻度处的交叉点检查。这种方法的问题在于,由于处理器在后台执行其他动画,因此在开始每个动画时很容易被阻止。请注意,我没有遇到其他两种方法的问题!

THIRD: Using NSTimer and this approach actually works but the animation can be jerky depending on what is going on around the screen. I use a timer tick of .1 sec and initiate a single animation of 10 degrees as well as a intersection check at every tick. The problem with this approach is that it is susceptible to being stalled when starting each animation due to the processor doing other animations in the background. Note that i didn't have this problem with the other two approaches!

第四:我尝试使用两者的组合。半径上的CABasicAnimation和点上的NSTimer。这个问题是,如果iDevice进入休眠状态然后恢复,它们可能会非常容易地发生。

FOURTH: I tried using a combination of the two. CABasicAnimation on the radius and NSTimer on the Points. This issue here is that they can get out of sync and happens quite easily if the iDevice goes to sleep and then resumes.

第五:使用iOS3.0风格的动画块旋转10度,持续时间为.1秒。使用animationDidStop方法设置委托和animationDidStopSelector,再次调用动画方法以及检查与点的交集。这也很有效,但很像第三种解决方案,当滚动和其他动画发生时,它是生涩的。这很可能是由动画的停止启动特性引起的。

FIFTH: Using the iOS3.0 style animation block and rotating 10 degrees with a duration of .1sec. Setting the delegate and the animationDidStopSelector with the animationDidStop method calling the animation method again as well as checking of intersection with points. This works too but much like the third solution, it is jerky when scrolling and other animations are happening. This is most likely caused by the stop start nature of the animation.

基本上,有没有办法动画视图无限但是在每个重复周期后调用一个方法?或者有没有办法让第三个解决方案更顺畅地工作?

Basically, is there a way to animation a view infinitely but make it call a method after every repeat cycle? Or is there a way to make the third solution work more smoothly?

请帮助,我已经完成了设计模式。

PLEASE HELP, I HAVE RUN OUT OF DESIGN PATTERNS.

推荐答案

好的,自从我发布这个问题以来,我已经走了很长的路。

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

公认的设计模式是实际上生成一个时钟节拍(通常使用CADisplayLink),以每秒30帧或60帧的速度运行,具体取决于您希望动画的平滑和快速程度。在每个帧回调中,您修改视图/图层上的变换并使用事务来显示它。

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];

无需每帧都继续创建新的转换,这只是浪费并消耗资源。最好创建一个名为rotationTransform的实例变量/属性,并修改每一帧并将其重新应用到图层/视图。

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

接下来,创建一个实际设置角度的方法,使用实例变量/ property用于存储角度并定义角度增量(我使用3度),也预定义2-pi,这样你就不会总是重新计算它。

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

最后,构建由CADisplayLink调用的方法设置框架并在保持帧同步的同时显示它。

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];

}

此帖子的代码摘录已经过大量修改,实际上我在同一个CADisplayLink实例中执行扫描线的动画和点的动画。

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.

这篇关于UIView无限循环动画在每个重复循环后调用一个方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆