完成后,在UIScrollView掩码中动画化CAGradientLayer的locations属性将重置

时间:2012-06-17 03:04:06

标签: iphone objective-c ios core-animation

CAGradientLayer到达某个位置时,我正试图动画UIScrollView的位置缩小。我将渐变设置为UIScrollView的蒙版,并调整渐变的locations属性以在滚动视图滚动时展开一些。这对我来说很好,除非我尝试动画更改位置。当我执行动画时 - 无论是作为显式CABasicAnimation还是隐式 - 动画都能正确执行,但无论出于何种原因,一旦动画完成,它就会将我的渐变(没有动画)的位置更改为其他的,非 - 零起点和终点。它每次都使用相同的值来执行此操作,并且在我的代码中的任何位置都没有指定这些值。

我对核心动画很新,所以也许我错过了一些东西,但据我所知,我的代码是正确的。我也尝试过等待执行动画,以解决滚动时的任何时间问题,但这也无济于事。

这是我的代码(相关部分,无论如何):

- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    gradientMask.position = CGPointMake(currentPageOffset, 0.0f);
    gradientMask.bounds = self.scrollView.bounds;
    [CATransaction commit];

    _animateGradientShrinkOnScroll = YES;

    // Reset scrollView contentOffset (I'm doing infinite paging)
    ...
}

- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat offset = self.scrollView.contentOffset.x;
    CGFloat relativeOffset = offset - currentPageOffset;

    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    gradientMask.position = self.scrollView.contentOffset;
    if (_animateGradientShrinkOnScroll)
        [CATransaction commit]; // if animating, set position w/o animation first

    CGFloat leftLength = ABS(relativeOffset);
    CGFloat rightLength = ABS(relativeOffset);

    CGFloat maxLength = [self maxGradientLength];
    leftLength = MIN((leftLength / 2), maxLength);
    rightLength = MIN((rightLength / 2), maxLength);

    // When animating, this effectively always goes from non-zero lengths to zero lengths,
    // and I've verified this by logging the values used.
    [self setGradientLeftLength:leftLength rightLength:rightLength animated:_animateGradientShrinkOnScroll];

    if (!_animateGradientShrinkOnScroll)
        [CATransaction commit];
    _animateGradientShrinkOnScroll = NO;
}

- (void) setGradientLeftLength:(CGFloat)leftLength rightLength:(CGFloat)rightLength animated:(BOOL)animated {
    CGFloat startRatio = MAX((leftLength / gradientMask.bounds.size.width), 0);
    CGFloat endRatio = 1.0f - MAX((rightLength / gradientMask.bounds.size.width), 0);

    NSArray *locations = [NSArray arrayWithObjects:
                          [NSNumber numberWithFloat:0.0f],
                          [NSNumber numberWithFloat:startRatio],
                          [NSNumber numberWithFloat:endRatio],
                          [NSNumber numberWithFloat:1.0f], nil];

    if (animated) {
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"locations"];
        animation.toValue = locations;
        [gradientMask addAnimation:animation forKey:kGradientMaskAnimationShrink];
    }
    else
        gradientMask.locations = locations;
}

1 个答案:

答案 0 :(得分:8)

向图层添加动画永远不会更改图层的属性。它只是激活屏幕上图层的外观。从图层中移除动画后,将根据图层的属性重新绘制图层。因此,您需要更改图层的属性,然后应用动画。在if语句中,请执行以下操作:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"locations"];
animation.fromValue = gradientMask.locations;
animation.toValue = locations;
gradientMask.locations = locations;
[gradientMask addAnimation:animation forKey:animation.keyPath];

为了更好地理解,请观看WWDC 2011中的“Core Animation Essentials”视频。这非常有帮助。