完成后会重置在UIScrollView蒙版中对CAGradientLayer的locations属性进行动画处理 [英] Animating CAGradientLayer's locations property in a UIScrollView mask resets after completion

查看:54
本文介绍了完成后会重置在UIScrollView蒙版中对CAGradientLayer的locations属性进行动画处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to animate the locations of a CAGradientLayer to shrink when the UIScrollView has reached a certain position. I have my gradient set up as a mask of the UIScrollView, and adjust the gradient's locations property to expand a bit as the scroll view scrolls. This works just fine for me, except when I try to animate a change to the locations. When I perform the animation - either as an explicit CABasicAnimation or implicitly - the animation performs correctly, but for whatever reason, once the animation is complete it then changes the locations of my gradient (without animation) to some other, non-zero start and end points. It uses the same values every single time to do this, and those values are not specified anywhere in my code.

我是Core Animation的新手,所以也许我遗漏了一些东西,但据我所知我的代码是正确的。我还尝试等待执行动画,以解决滚动时出现的任何计时问题,但这也无济于事。

I'm fairly new to Core Animation, so maybe I'm missing something, but as far as I can tell my code is correct. I've also tried waiting to perform the animation, to account for any timing issues with my scrolling, but that didn't help either.

这是我的代码(相关代码部分):

Here's my code (the relevant parts, anyway):

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


推荐答案

将动画添加到图层从不更改图层的属性。它只是使图层在屏幕上的外观动起来。将动画从图层中删除后,将根据其属性重新绘制图层。因此,您需要更改图层的属性,然后应用动画。在您的 if 语句中,执行以下操作:

Adding an animation to a layer never changes the layer's properties. It just animates the layer's appearance on screen. Once the animation is removed from the layer, the layer is redrawn based on its properties. So you need to change the layer's properties, then apply the animation. In your if statement, do this:

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

为了更好地理解,请观看 WWDC 2011 。这很有帮助。

For a better understanding, watch the "Core Animation Essentials" video from WWDC 2011. It is very helpful.

这篇关于完成后会重置在UIScrollView蒙版中对CAGradientLayer的locations属性进行动画处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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