4

が特定の位置に達したCAGradientLayerときに収縮するようにアニメーション化しようとしています。UIScrollViewグラデーションを のマスクとして設定しUIScrollView、グラデーションのlocationsプロパティを調整して、スクロール ビューのスクロールに合わせて少し拡張します。場所の変更をアニメーション化しようとする場合を除いて、これは私にとってはうまく機能します。明示的CABasicAnimationまたは暗黙的にアニメーションを実行すると、アニメーションは正しく実行されますが、何らかの理由で、アニメーションが完了すると、グラデーションの位置が (アニメーションなしで) 他のゼロ以外の開始点と終了点に変更されます。ポイント。これを行うために毎回同じ値を使用しますが、それらの値はコードのどこにも指定されていません。

私は Core Animation にかなり慣れていないので、何か不足している可能性がありますが、私のコードが正しいと言える限りです。また、スクロールのタイミングの問題を考慮して、アニメーションの実行を待機しようとしましたが、それも役に立ちませんでした。

これが私のコードです(とにかく関連部分):

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

1 に答える 1

8

アニメーションをレイヤーに追加しても、レイヤーのプロパティは変更されません。画面上のレイヤーの外観をアニメーション化するだけです。アニメーションがレイヤーから削除されると、レイヤーはそのプロパティに基づいて再描画されます。したがって、レイヤーのプロパティを変更してから、アニメーションを適用する必要があります。あなたのif声明では、これを行います:

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

理解を深めるには、WWDC2011の「CoreAnimationEssentials」ビデオをご覧ください。とても助かります。

于 2012-06-17T03:30:25.103 に答える