CADisplayLink& UIView动画不可靠

时间:2014-04-02 13:01:44

标签: iphone objective-c uiview cadisplaylink

我正在尝试创建一个Animations Manager类,它将为我处理递归动画。它工作正常,但不可靠。例如,有时候,使用它时,动画会发生并且背靠背"因为它们之间没有延迟。其他时候使用它时,动画之间会有延迟(这种情况发生在其他视图控制器上的其他元素上)

这是我的代码:

@implementation customAnimationTimer

-(id) initWithTimeInterval:(NSTimeInterval)timeInterval target:(UIView*)target animationType:(NSInteger)animationType
              fromValue:(CGFloat)fromValue toValue:(CGFloat)toValue withDelegate:(id <customAnimationTimerDelegate>)delegate {

    if (self = [super init]) {
        self.delegate = delegate;
        _timeInterval = timeInterval;
        _target = target;
        _animationState = NO;
        _animationType = animationType;
        _fromValue = fromValue;
        _toValue = toValue;

        _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkFire)];
        [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    }
    return self;
}

-(void) displayLinkFire {if (self.delegate) [self.delegate displayLinkUpdate:self];}

@end


@implementation animationManager


static animationManager* sharedHelper = nil;

+ (animationManager*) sharedInstance {
    if (!sharedHelper) sharedHelper = [[animationManager alloc] init];
    return sharedHelper;
}


-(id) init { if (self = [super init]) {[self initArrays];} return self;}

-(void) initArrays {
    _activeTimers = [NSMutableArray arrayWithObjects: nil];
}

-(void) displayLinkUpdate:(customAnimationTimer*)timer {
    if (timer.displayLink.frameInterval != 1) [self animateWithTimer:timer];
    timer.displayLink.frameInterval = (timer.timeInterval/timer.displayLink.duration);
}

-(void) animateWithTimer:(customAnimationTimer*)timer {
    if (!timer.animationState) {

        timer.animationState = true;
        [UIView animateWithDuration:timer.timeInterval animations:^{
           if (timer.animationType == 0) timer.target.alpha = timer.toValue;
        }];

    } else {

        timer.animationState = false;
        [UIView animateWithDuration:timer.timeInterval animations:^{
            if (timer.animationType == 0) timer.target.alpha = timer.fromValue;
        }];

    }
}

-(void) addAnimationToView:(UIView*)view withType:(int)animationType fromValue:(CGFloat)fromValue toValue:(CGFloat)toValue withTime:(CGFloat)time  {
    [_activeTimers addObject: [[customAnimationTimer alloc] initWithTimeInterval:time target:view animationType:animationType fromValue:fromValue toValue:toValue withDelegate:self]];
}

-(void) removeAnimationFromView:(UIView*)view {

    NSInteger index = 900000000;
    for (customAnimationTimer* timer in _activeTimers) {
        if (timer.target == view) {
            index = [_activeTimers indexOfObject:timer];
            [timer.displayLink invalidate];
        }
    }

    if (index != 900000000) [_activeTimers removeObjectAtIndex:index];

}

-(void) removeAnimations {
    for (customAnimationTimer* timer in _activeTimers) [timer.displayLink invalidate];
    [self initArrays];
}


@end

2 个答案:

答案 0 :(得分:0)

您可能正在模拟器中进行测试。唐&#39;吨。 CADisplayLink在模拟器中完全不可靠。如果您要使用CADisplayLink,请仅在设备上进行测试。

您的代码的另一个问题是您永远不应该假设CADisplayLink会触发的频率。它不会定期开火。始终查看timestamp以了解实际实施的时间,并计算动画&#34;框架&#34;基于此。

在我自己的代码的这个例子中,我调用了第一个&#34; frame&#34;动画0和最后一帧&#34;帧&#34;整个动画1。因此我可以计算出正确的#34;框架#34;通过比较时间戳和总持续时间来动画。我在一些实例变量中维护状态。以下是显示链接触发时发生的情况:

if (self->_timestamp < 0.01) { // pick up and store first timestamp
    self->_timestamp = sender.timestamp;
    self->_frame = 0.0;
} else { // calculate frame
    self->_frame = (sender.timestamp - self->_timestamp) * SCALE;
}
// ... redraw here ...
if (self->_frame > 1.0) {
    [sender invalidate];
    self->_frame = 0.0;
    self->_timestamp = 0.0;
}

答案 1 :(得分:0)

好吧,录制完并播放了两张唱片,我的眼睛确实是我的伎俩!其中一个是蓝色背景,另一个是红色背景,我想这与它有关!我向那些我困惑的人道歉!