3D 动画 - CABasicAnimation 和 CATransform3D 提供视图之间的差距
Posted
技术标签:
【中文标题】3D 动画 - CABasicAnimation 和 CATransform3D 提供视图之间的差距【英文标题】:3D Animation - CABasicAnimation and CATransform3D giving gap between views 【发布时间】:2012-04-09 09:10:22 【问题描述】:所以,我正在尝试在第一个视图中的这个应用程序http://itunes.apple.com/us/app/spg-mobile-app/id312306003?mt=8 中实现一个动画
我已经实现了翻转视图的动画,并且我成功地为一侧设置动画,当我给出反向翻转的反向逻辑时,它会在视图之间产生一些差距
这是我的代码
- (UIImage *)screenShot: (UIView *) aView
// Arbitrarily masks to 40%. Use whatever level you like
UIGraphicsBeginImageContext(hostView.frame.size);
[aView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGContextSetRGBFillColor (UIGraphicsGetCurrentContext(), 0, 0, 0, 0.4f);
CGContextFillRect (UIGraphicsGetCurrentContext(), hostView.frame);
UIGraphicsEndImageContext();
return image;
- (CALayer *) createLayerFromView: (UIView *) aView transform: (CATransform3D) transform
CALayer *imageLayer = [CALayer layer];
imageLayer.anchorPoint = CGPointMake(1.0f, 1.0f);
imageLayer.frame = (CGRect).size = hostView.frame.size;
imageLayer.transform = transform;
UIImage *shot = [self screenShot:aView];
imageLayer.contents = (__bridge id) shot.CGImage;
return imageLayer;
- (void)animationDidStart:(CAAnimation *)animation
UIView *source = (UIView *) _source;
[source removeFromSuperview];
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
UITableView *dest = (UITableView *) destination;
dest.frame = CGRectMake(160, 0, 160, 460);
[hostView addSubview:dest];
[transformationLayer removeFromSuperlayer];
//if (delegate)
//SAFE_PERFORM_WITH_ARG(delegate, @selector(segueDidComplete), nil);
-(void)animateWithDuration: (CGFloat) aDuration
goesForward=FALSE ;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.delegate = self;
group.duration = aDuration;
CGFloat halfWidth = hostView.frame.size.width; // 2.0f;
float multiplier = goesForward ? -1.0f : 1.0f;
CABasicAnimation *translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"];
translationX.toValue = [NSNumber numberWithFloat:multiplier * halfWidth];
CABasicAnimation *translationZ = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.z"];
translationZ.toValue = [NSNumber numberWithFloat:-200.0]; //halfWidth];
CABasicAnimation *rotationY = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"];
rotationY.toValue = [NSNumber numberWithFloat: multiplier * M_PI_2];
group.animations = [NSArray arrayWithObjects: rotationY, translationX, translationZ, nil];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[CATransaction flush];
[transformationLayer addAnimation:group forKey:kAnimationKey];
- (void) constructRotationLayer
UIView *source = (UIView *) _source;
UIView *dest = (UIView *) destination;
hostView = [source superview];
// if ([hostView isKindOfClass:[UIWindow class]])
// NSLog(@"I am window class");
//
transformationLayer = [CALayer layer];
transformationLayer.frame = hostView.bounds; //CGRectMake(40, 0, 280, 460);
transformationLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
CATransform3D sublayerTransform = CATransform3DIdentity;
sublayerTransform.m34 = 1.0 / -1000;
[transformationLayer setSublayerTransform:sublayerTransform];
[hostView.layer addSublayer:transformationLayer];
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:source transform:CATransform3DRotate(transform, M_PI_2, 0, 0, 0)]];
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
if (!goesForward)
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:dest transform:transform]];
- (void)perform
[self constructRotationLayer];
[self animateWithDuration:0.4f];
所以,这里我先调用 perform 方法 在这里我上传了我的总代码Here
这段代码对我有点用,但仍然有一些差距,问题是当前视图的框架和即将到来的视图应该相同
- (UIImage *)screenShot: (UIView *) aView
// Arbitrarily masks to 40%. Use whatever level you like
UIGraphicsBeginImageContext(hostView.frame.size);
[aView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGContextSetRGBFillColor (UIGraphicsGetCurrentContext(), 0, 0, 0, 0.4f);
CGContextFillRect (UIGraphicsGetCurrentContext(), hostView.frame);
UIGraphicsEndImageContext();
return image;
- (CALayer *) createLayerFromView: (UIView *) aView transform: (CATransform3D) transform
CALayer *imageLayer = [CALayer layer];
imageLayer.anchorPoint = CGPointMake(1.0f, 1.0f);
imageLayer.frame = (CGRect).size = hostView.frame.size;
imageLayer.transform = transform;
UIImage *shot = [self screenShot:aView];
imageLayer.contents = (__bridge id) shot.CGImage;
return imageLayer;
- (void)animationDidStart:(CAAnimation *)animation
// UIView *source = (UIView *) super.sourceViewController;
[source removeFromSuperview];
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
// UIView *dest = (UIView *) super.destinationViewController;
if (hostView !=nil)
NSLog(@"hostView %@",hostView);
if (dest)
[hostView addSubview:dest];
[transformationLayer removeFromSuperlayer];
if (delegate)
SAFE_PERFORM_WITH_ARG(delegate, @selector(segueDidComplete), nil);
-(void)animateWithDuration: (CGFloat) aDuration
CAAnimationGroup *group = [CAAnimationGroup animation];
group.delegate = self;
group.duration = aDuration;
CGFloat halfWidth = hostView.frame.size.width / 2.0f;
float multiplier = goesForward ? -1.0f : 1.0f;
CABasicAnimation *translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"];
translationX.toValue = [NSNumber numberWithFloat:multiplier * halfWidth];
CABasicAnimation *translationZ = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.z"];
translationZ.toValue = [NSNumber numberWithFloat:-halfWidth];
CABasicAnimation *rotationY = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"];
rotationY.toValue = [NSNumber numberWithFloat: multiplier * M_PI_2];
group.animations = [NSArray arrayWithObjects: rotationY, translationX, translationZ, nil];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[CATransaction flush];
[transformationLayer addAnimation:group forKey:kAnimationKey];
- (void) constructRotationLayer
// UIView *source = (UIView *) super.sourceViewController;
// UIView *dest = (UIView *) super.destinationViewController;
hostView = source.superview;
transformationLayer = [CALayer layer];
transformationLayer.frame = hostView.bounds;
transformationLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
CATransform3D sublayerTransform = CATransform3DIdentity;
sublayerTransform.m34 = 1.0 / -1000;
[transformationLayer setSublayerTransform:sublayerTransform];
[hostView.layer addSublayer:transformationLayer];
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:source transform:transform]];
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
if (!goesForward)
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:dest transform:transform]];
- (void)perform
[self constructRotationLayer];
[self animateWithDuration:0.4f];
【问题讨论】:
示例代码不完整。它不会构建,因为它缺少 RotatingFlipSegue 的文件 @Charan 我也需要那个视图。你能分享一下吗?如果您将演示代码上传到 git 并与我们分享,那就太好了。 【参考方案1】:终于解决了我的问题,搞砸了锚点
- (UIImage *)screenShot: (UIView *) aView
// Arbitrarily masks to 40%. Use whatever level you like
UIGraphicsBeginImageContext(hostView.frame.size);
[aView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGContextSetRGBFillColor (UIGraphicsGetCurrentContext(), 0, 0, 0, 0.4f);
CGContextFillRect (UIGraphicsGetCurrentContext(), hostView.frame);
UIGraphicsEndImageContext();
return image;
- (CALayer *) createLayerFromView: (UIView *) aView transform: (CATransform3D) transform
CALayer *imageLayer = [CALayer layer];
imageLayer.anchorPoint = CGPointMake(1.0f, 1.0f);
imageLayer.frame = (CGRect).size = hostView.frame.size;
imageLayer.transform = transform;
UIImage *shot = [self screenShot:aView];
imageLayer.contents = (__bridge id) shot.CGImage;
return imageLayer;
- (void)animationDidStart:(CAAnimation *)animation
// UIView *source = (UIView *) super.sourceViewController;
[source removeFromSuperview];
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
// UIView *dest = (UIView *) super.destinationViewController;
if (hostView !=nil)
NSLog(@"hostView %@",hostView);
if (dest)
[hostView addSubview:dest];
[transformationLayer removeFromSuperlayer];
if (delegate)
SAFE_PERFORM_WITH_ARG(delegate, @selector(segueDidComplete), nil);
-(void)animateWithDuration: (CGFloat) aDuration
CAAnimationGroup *group = [CAAnimationGroup animation];
group.delegate = self;
group.duration = aDuration;
CGFloat halfWidth = hostView.frame.size.width / 2.0f;
float multiplier = goesForward ? -1.0f : 1.0f;
CABasicAnimation *translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"];
translationX.toValue = [NSNumber numberWithFloat:multiplier * halfWidth];
CABasicAnimation *translationZ = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.z"];
translationZ.toValue = [NSNumber numberWithFloat:-halfWidth];
CABasicAnimation *rotationY = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"];
rotationY.toValue = [NSNumber numberWithFloat: multiplier * M_PI_2];
group.animations = [NSArray arrayWithObjects: rotationY, translationX, translationZ, nil];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[CATransaction flush];
[transformationLayer addAnimation:group forKey:kAnimationKey];
- (void) constructRotationLayer
// UIView *source = (UIView *) super.sourceViewController;
// UIView *dest = (UIView *) super.destinationViewController;
hostView = source.superview;
transformationLayer = [CALayer layer];
transformationLayer.frame = hostView.bounds;
transformationLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
CATransform3D sublayerTransform = CATransform3DIdentity;
sublayerTransform.m34 = 1.0 / -1000;
[transformationLayer setSublayerTransform:sublayerTransform];
[hostView.layer addSublayer:transformationLayer];
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:source transform:transform]];
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
if (!goesForward)
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:dest transform:transform]];
- (void)perform
[self constructRotationLayer];
[self animateWithDuration:0.4f];
【讨论】:
【参考方案2】:我也是这样做的。我的工作代码如下。请喜欢它。
- (UIImage *)screenShot: (UIView*) aView
// Arbitrarily masks to 40%. Use whatever level you like
UIGraphicsBeginImageContext(hostView.frame.size);
[aView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGContextSetRGBFillColor (UIGraphicsGetCurrentContext(), 0, 0, 0, 0.4f);
CGContextFillRect (UIGraphicsGetCurrentContext(), hostView.frame);
UIGraphicsEndImageContext();
return image;
- (CALayer*) createLayerFromView: (UIView *) aView transform: (CATransform3D) transform
CALayer *imageLayer = [CALayer layer];
imageLayer.anchorPoint = CGPointMake(1.0f, 1.0f);
imageLayer.frame = (CGRect).size = hostView.frame.size;
imageLayer.transform = transform;
UIImage *shot = [self screenShot:aView];
imageLayer.contents = (id) shot.CGImage;
return imageLayer;
- (void)animationDidStart:(CAAnimation *)animation
UIViewController *source;
if (islogin)
source = (UIViewController *)self.navigationController;
else
source = (UIViewController *)self.joinTABBARController;
[source.view removeFromSuperview];
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
UIViewController *dest;
if (islogin)
dest = (UIViewController *) self.joinTABBARController;
else
dest = (UIViewController *)self.navigationController;
[hostView addSubview:dest.view];
[transformationLayer removeFromSuperlayer];
// if (delegate)
// SAFE_PERFORM_WITH_ARG(delegate, @selector(segueDidComplete), nil);
//-(void)animateWithDuration: (CGFloat) aDuration
//
// CAAnimationGroup *group = [CAAnimationGroup animation];
// group.delegate = self;
// group.duration = aDuration;
//
// CGFloat halfWidth = hostView.frame.size.width / 2.0f;
// float multiplier = goesForward ? -1.0f : 1.0f;
//
// CABasicAnimation *translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"];
// translationX.toValue = [NSNumber numberWithFloat:multiplier * halfWidth];
//
// CABasicAnimation *translationZ = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.z"];
// translationZ.toValue = [NSNumber numberWithFloat:-halfWidth];
//
// CABasicAnimation *rotationY = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"];
// rotationY.toValue = [NSNumber numberWithFloat: multiplier * M_PI_2];
//
// group.animations = [NSArray arrayWithObjects: rotationY, translationX, translationZ, nil];
// group.fillMode = kCAFillModeForwards;
// group.removedOnCompletion = NO;
//
// [CATransaction flush];
// [transformationLayer addAnimation:group forKey:kAnimationKey];
//
- (void) constructRotationLayer:(TranDirection)aDirection
UIViewController *source;
UIViewController *dest;
if (islogin)
source = (UIViewController *) self.navigationController;
dest = (UIViewController*) self.joinTABBARController;
else
source = (UIViewController *) self.joinTABBARController;
dest = (UIViewController *) self.navigationController;
hostView = source.view.superview;
transformationLayer = [CALayer layer];
transformationLayer.frame = hostView.bounds;
transformationLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
CATransform3D sublayerTransform = CATransform3DIdentity;
sublayerTransform.m34 = 1.0 / -1000;
[transformationLayer setSublayerTransform:sublayerTransform];
[hostView.layer addSublayer:transformationLayer];
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:source.view transform:transform]];
// transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
// transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
// if (!goesForward)
//
// transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
// transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
// transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
// transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
//
//
// [transformationLayer addSublayer:[self createLayerFromView:dest.view transform:transform]];
if (aDirection == RTOL)
transform = CATransform3DRotate(transform, radians(90), 0, 1, 0);
transform = CATransform3DTranslate(transform, CUBESIZE, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:dest.view transform:transform]];
else
transform = CATransform3DRotate(transform, radians(90), 0, 1, 0);
transform = CATransform3DTranslate(transform, CUBESIZE, 0, 0);
transform = CATransform3DRotate(transform, radians(90), 0, 1, 0);
transform = CATransform3DTranslate(transform, CUBESIZE, 0, 0);
transform = CATransform3DRotate(transform, radians(90), 0, 1, 0);
transform = CATransform3DTranslate(transform, CUBESIZE, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:dest.view transform:transform]];
-(void)moveFrom:(TranDirection)aDirection duration:(float)aDuration
[CATransaction flush];
CABasicAnimation *rotation;
CABasicAnimation *translationX;
CABasicAnimation *translationZ;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.delegate = self;
group.duration = aDuration;
if (aDirection == RTOL)
translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"];
translationX.toValue = [NSNumber numberWithFloat:-(CUBE_VERTICAL_WIDTH / 2)];
rotation = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"];
rotation.toValue = [NSNumber numberWithFloat:radians(-90)];
else
translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"];
translationX.toValue = [NSNumber numberWithFloat:(CUBE_VERTICAL_WIDTH / 2)];
rotation = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"];
rotation.toValue = [NSNumber numberWithFloat:radians(90)] ;
translationZ = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.z"];
translationZ.toValue = [NSNumber numberWithFloat:-(CUBE_VERTICAL_WIDTH / 2)];
group.animations = [NSArray arrayWithObjects: rotation, translationX, translationZ, nil];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[transformationLayer addAnimation:group forKey:kAnimationKey];
- (void)perform:(TranDirection)tdir
[self constructRotationLayer:tdir];
// [self animateWithDuration:2.0f];
[self moveFrom:tdir duration:.4];
【讨论】:
但我的问题是在反转翻转动画时,视图之间出现了差距 我必须在 z 轴上前后移动沙袋,所以在这方面有任何建议..以上是关于3D 动画 - CABasicAnimation 和 CATransform3D 提供视图之间的差距的主要内容,如果未能解决你的问题,请参考以下文章