【问题标题】:Unexpected CALayer Vertical Flipping on 3D Rotation 'Bounce'3D 旋转“反弹”上的意外 CALayer 垂直翻转
【发布时间】:2023-03-10 20:29:01
【问题描述】:

我正在尝试创建一个包含CALayer 单元格的翻转过渡,这些单元格在完成后翻转并“反弹”。但是,我遇到了 this video 中显示的奇怪垂直翻转问题。如果没有最后的“反弹”动画,则动画按预期工作,因此与图像本身无关,也与在制作动画之前将图像拼接到各个单元格层无关。

动画代码(每个CALayer 单元格)

@interface transitionCell : CALayer

@property (nonatomic) UIImage* startImage;
@property (nonatomic) UIImage* endImage;

@property (nonatomic, readonly) BOOL animationDidFinish;
@property (nonatomic, readonly) BOOL isAnimating;

@property (nonatomic) CGFloat zRotateFactor;

@end

@implementation transitionCell

-(void) setStartImage:(UIImage *)startImage {
    self.contents = (__bridge id)startImage.CGImage;
}

-(void) startAnimationWithDuration:(CGFloat)duration { // First half of rotation

    _isAnimating = YES;

    CABasicAnimation* yRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    yRotation.fromValue = @(0);
    yRotation.toValue = @(M_PI*0.5);

    CABasicAnimation* zRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    zRotation.fromValue = @(0);
    zRotation.toValue = @(zRotateMax*_zRotateFactor); // zRotateMax is M_PI*0.2 & _zRotateFactor is a value between -1 and 1.

    CAAnimationGroup* rotations = [CAAnimationGroup animation];
    rotations.duration = duration*0.5;
    rotations.delegate = self;
    rotations.removedOnCompletion = NO;
    rotations.fillMode = kCAFillModeForwards;
    rotations.animations = @[yRotation, zRotation];

    [self addAnimation:rotations forKey:@"startRotation"];
}

-(void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { // Second half of rotation

    if (anim == [self animationForKey:@"startRotation"] && flag) {

        self.contents = (__bridge id)_endImage.CGImage;

        CABasicAnimation* yRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
        yRotation.toValue = @(M_PI);
        yRotation.fromValue = @(M_PI*0.5);

        CABasicAnimation* zRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        zRotation.toValue = @(0);
        zRotation.fromValue = @(zRotateMax*_zRotateFactor);

        CAAnimationGroup* rotations = [CAAnimationGroup animation];
        rotations.duration = anim.duration;
        rotations.removedOnCompletion = NO;
        rotations.fillMode = kCAFillModeForwards;
        rotations.delegate = self;
        rotations.animations = @[yRotation, zRotation];
        [self addAnimation:rotations forKey:@"endRotate"];

    } else if (anim == [self animationForKey:@"endRotate"] && flag) { // The 'Bounce' animation (the one causing the issues)

        CABasicAnimation* yRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
        yRotation.toValue = @(M_PI+(M_PI*0.2));
        yRotation.fromValue = @(M_PI);

        CABasicAnimation* zRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        zRotation.fromValue = @(0);
        zRotation.toValue = @(-zRotateMax*_zRotateFactor*0.2);

        CAAnimationGroup* rotations = [CAAnimationGroup animation];
        rotations.duration = 0.2;
        rotations.removedOnCompletion = NO;
        rotations.fillMode = kCAFillModeForwards;
        rotations.delegate = self;
        rotations.autoreverses = YES;
        rotations.animations = @[yRotation, zRotation];
        [self addAnimation:rotations forKey:@"endRotate2"];

    } else if (anim  == [self animationForKey:@"endRotate2"] && flag) {
        _animationDidFinish = YES;
    }
}

@end

初始化代码(在父UIViewController中)

-(instancetype) initWithStartImage:(UIImage*)startImage endImage:(UIImage*)endImage {
    if (self = [super init]) {

        CGFloat baseNodeHeight = screenWidth()/baseNumberNodesWidth;

        numNodesHeight = roundf(screenHeight()/baseNodeHeight);
        numNodesWidth = roundf(screenWidth()/baseNodeHeight);

        moveUpdateFreq = moveBaseUpdateFreq/(numNodesWidth*numNodesHeight);
        cellMoveUpdateFreq = cellMoveBaseUpdateFreq/(numNodesWidth*numNodesHeight);

        CGFloat const nodeWidth = screenWidth()/numNodesWidth;
        CGFloat const nodeHeight = screenHeight()/numNodesHeight;

        transition = (transitionType)arc4random_uniform(transitionTypeCount);

        cellArray = [NSMutableArray array];

        for (int x = 0; x < numNodesWidth; x++) {

            [cellArray addObject:[NSMutableArray array]];

            for (int y = 0; y < numNodesHeight; y++) {

                transitionCell* c = [transitionCell layer];
                c.frame = (CGRect){{x*nodeWidth, y*nodeHeight}, {nodeWidth, nodeHeight}};

                CGRect startSubRect = {{c.frame.origin.x, screenHeight()-c.frame.origin.y-c.frame.size.height}, c.frame.size};
                CGRect endSubRect = {{c.frame.origin.x, c.frame.origin.y}, c.frame.size};

                c.startImage = [startImage imageFromSubRect:startSubRect];
                c.endImage = [[endImage flippedVerticalImage] imageFromSubRect:endSubRect];

                c.zRotateFactor = -(((CGFloat)y-((CGFloat)numNodesHeight*0.5))/(CGFloat)numNodesHeight);

                [self.view.layer addSublayer:c];
                [cellArray[x] addObject:c];

            }
        }

    }
    return self;
}

任何想法我做错了什么?

【问题讨论】:

  • 所以self这里是UITableViewCell的子类?
  • @Unheilig 不,它们是CALayer 的子类。抱歉,在我发布其余代码之前,我停电了。

标签: ios objective-c animation core-animation calayer


【解决方案1】:

好吧,我只能假设这是一个错误,但我还是找到了一个快速修复。通过在“反弹”动画上添加一个 xRotation 动画集以从 pi 到 pi,问题得到解决。例如在弹跳动画代码中:

// Bounce animation

CABasicAnimation* yRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
yRotation.toValue = @(M_PI+(M_PI*bounceFactor));
yRotation.fromValue = @(M_PI);

CABasicAnimation* zRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
zRotation.fromValue = @(0);
zRotation.toValue = @(-zRotateMax*_zRotateFactor*bounceFactor);

// New animation, set to do nothing on the x-axis
CABasicAnimation* xRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
xRotation.toValue = @(M_PI);
xRotation.fromValue = @(M_PI);

CAAnimationGroup* rotations = [CAAnimationGroup animation];
rotations.duration = 0.2;
rotations.removedOnCompletion = NO;
rotations.fillMode = kCAFillModeForwards;
rotations.delegate = self;
rotations.autoreverses = YES;
rotations.animations = @[yRotation, zRotation, xRotation];
[self addAnimation:rotations forKey:@"endRotate2"];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-28
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 2012-03-25
    相关资源
    最近更新 更多