沿锚点旋转 CATransformLayer
Posted
技术标签:
【中文标题】沿锚点旋转 CATransformLayer【英文标题】:Rotating CATransformLayer along anchorpoint 【发布时间】:2012-08-24 20:10:45 【问题描述】:构建一个由 6 面组成的立方体:每面都是一个 CALayer,然后每个都作为子视图添加到 (6) CATransformLayers(以启用 3d 转换)。 这 6 个 CATransformLayer 作为子视图添加到单个 CATransformLayer。
当旋转这个单独的 CATransformLayer 将整个立方体作为一个包进行旋转时,一切正常,我将锚点设置为 0,0,将锚点 Z 设置为立方体的中间:立方体完美地围绕其中心旋转。
问题: 我想“展开”当前侧的 4 个相邻侧,这意味着左侧、右侧、上方和下方的侧向用户旋转 90*,但仍坚持面向用户的一侧。
为此,例如我将当前边上方的anchorpointZ设置为0,将anchorpoint设置为(0.5,1),这样anchorpoint基本上是公共边的中间。
设置立方体:
transformLayer = [CATransformLayer layer];
transformLayer.position = CGPointMake([UIScreen mainScreen].bounds.size.width/2,[UIScreen mainScreen].bounds.size.height/2);
CGRect layerRect = CGRectMake(0.0, 0.0, 150, 150); //frame rect for cube sides
CGPoint screenCenter = CGPointMake(self.transformLayer.bounds.size.width / 2, self.transformLayer.bounds.size.height / 2);
//side1
side1 = [CALayer layer];
side1.borderColor = [UIColor colorWithHue:0.6 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side1.backgroundColor = [UIColor colorWithHue:0.6 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side1.borderWidth = 2.0;
side1.cornerRadius = 30.0;
side1.frame = layerRect;
side1.position = screenCenter;
side1t = [CATransformLayer layer];
[side1t addSublayer:side1];
//side2
side2 = [CALayer layer];
side2.borderColor = [UIColor colorWithHue:0.25 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side2.backgroundColor = [UIColor colorWithHue:0.25 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side2.borderWidth = 2.0;
side2.cornerRadius = 30.0;
side2.frame = layerRect;
side2.position = screenCenter;
//positioning
CATransform3D rotation = CATransform3DMakeRotation(M_PI/2, 0.0, 1.0, 0.0);
CATransform3D translation = CATransform3DMakeTranslation(150/2, 0.0, 150/-2 );
CATransform3D position = CATransform3DConcat(rotation, translation);
side2.transform = position;
side2t = [CATransformLayer layer];
[side2t addSublayer:side2];
//side3
side3 = [CALayer layer];
side3.borderColor = [UIColor colorWithHue:0.0 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side3.backgroundColor = [UIColor colorWithHue:0.0 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side3.borderWidth = 2.0;
side3.cornerRadius = 30.0;
side3.frame = layerRect;
side3.position = screenCenter;
//positioning
translation = CATransform3DMakeTranslation(0.0, 0.0, -150); //150
side3.transform = translation;
side3t = [CATransformLayer layer];
[side3t addSublayer:side3];
//side4
side4 = [CALayer layer];
side4.borderColor = [UIColor colorWithHue:0.2 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side4.backgroundColor = [UIColor colorWithHue:0.2 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side4.borderWidth = 2.0;
side4.cornerRadius = 30.0;
side4.frame = layerRect;
side4.position = screenCenter;
//positioning
rotation = CATransform3DMakeRotation(M_PI/2, 0.0, 1.0, 0.0);
translation = CATransform3DMakeTranslation(150/-2, 0.0, 150/-2);
side4.transform = CATransform3DConcat(rotation, translation);
side4t = [CATransformLayer layer];
[side4t addSublayer:side4];
//side5
side5 = [CALayer layer];
side5.borderColor = [UIColor colorWithHue:0.8 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side5.backgroundColor = [UIColor colorWithHue:0.8 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side5.borderWidth = 2.0;
side5.cornerRadius = 30.0;
side5.frame = layerRect;
side5.position = screenCenter;
//positioning
rotation = CATransform3DMakeRotation(M_PI/2, 1.0, .0, 0.0);
translation = CATransform3DMakeTranslation(0.0, 150/-2, 150/-2);
side5.transform = CATransform3DConcat(rotation, translation);
side5t = [CATransformLayer layer];
[side5t addSublayer:side5];
//side6
side6 = [CALayer layer];
side6.borderColor = [UIColor colorWithHue:0.0845 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side6.backgroundColor = [UIColor colorWithHue:0.0845 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side6.borderWidth = 2.0;
side6.cornerRadius = 30.0;
side6.frame = layerRect;
side6.position = screenCenter;
//positioning
rotation = CATransform3DMakeRotation(M_PI/2, 1.0, .0, 0.0);
translation = CATransform3DMakeTranslation(0.0, 150/2, 150/-2);
side6.transform = CATransform3DConcat(rotation, translation);
side6t = [CATransformLayer layer];
[side6t addSublayer:side6];
[self.transformLayer addSublayer:side1t];
[self.transformLayer addSublayer:side2t];
[self.transformLayer addSublayer:side3t];
[self.transformLayer addSublayer:side4t];
[self.transformLayer addSublayer:side5t];
[self.transformLayer addSublayer:side6t];
self.transformLayer.anchorPointZ = -150/2;
[self.layer addSublayer: transformLayer];
这部分不起作用。旋转(90°)是正确的,但侧面最终处于完全错误的位置,当前侧面前面的立方体大小的一半(z 坐标)并在 x-y 空间中覆盖了正面的一半,见截图
-(void)unfoldUpperSide
[CATransaction begin];
[CATransaction setAnimationDuration: 3.0];
side5t.anchorPoint = CGPointMake(0.5, 0);
side5t.anchorPointZ = 0;
side5t.transform = CATransform3DMakeRotation(-M_PI/2, 1, 0, 0);
[CATransaction commit];
我整天都被困在这个问题上,希望有人能帮助我..!
【问题讨论】:
【参考方案1】:您不需要为每一层制作一个 CATransformLayer,一个单独的 CATransformLayer 来容纳所有层就足够了,您仍然可以制作 3d 变换,因为 CATransformLayer 变换适用于其中层的所有锚点。
为什么你的个别边的旋转关闭是因为所有边的anchorPoint是0.5,0.5(即它们各自的中心,所以你围绕那个中心旋转)
您可以通过在两个所需方向上将层平移一半大小来解决此问题,同时旋转层,尽管最初有轻微的剪裁,这是下面的 osx 代码,只需将 NSColor 等更改为 UIKit 对应项。
-(void)cubeTest
float size = 100.0;
CATransformLayer *transformLayer = [CATransformLayer layer];
transformLayer.position = CGPointMake(cubeView.bounds.size.width/2,cubeView.bounds.size.height/2);
CGRect layerRect = CGRectMake(0.0, 0.0, size, size); //frame rect for cube sides
CGPoint screenCenter = CGPointMake(transformLayer.bounds.size.width / 2, transformLayer.bounds.size.height / 2);
//side1
CALayer *side1 = [CALayer layer];
side1.borderColor = [NSColor colorWithHue:0.6 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side1.backgroundColor = [NSColor colorWithHue:0.6 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side1.borderWidth = 2.0;
side1.cornerRadius = 30.0;
side1.frame = layerRect;
side1.position = screenCenter;
[transformLayer addSublayer:side1];
//side2
CALayer *side2 = [CALayer layer];
side2.borderColor = [NSColor colorWithHue:0.25 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side2.backgroundColor = [NSColor colorWithHue:0.25 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side2.borderWidth = 2.0;
side2.cornerRadius = 30.0;
side2.frame = layerRect;
side2.position = screenCenter;
//positioning
CATransform3D rotation = CATransform3DMakeRotation(M_PI/2, 0.0, 1.0, 0.0);
CATransform3D translation = CATransform3DMakeTranslation(size/2, 0.0, size/-2 );
CATransform3D position = CATransform3DConcat(rotation, translation);
side2.transform = position;
[transformLayer addSublayer:side2];
//side3
CALayer *side3 = [CALayer layer];
side3.borderColor = [NSColor colorWithHue:0.0 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side3.backgroundColor = [NSColor colorWithHue:0.0 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side3.borderWidth = 2.0;
side3.cornerRadius = 30.0;
side3.frame = layerRect;
side3.position = screenCenter;
//positioning
translation = CATransform3DMakeTranslation(0.0, 0.0, -size); //size
side3.transform = translation;
[transformLayer addSublayer:side3];
//side4
CALayer *side4 = [CALayer layer];
side4.borderColor = [NSColor colorWithHue:0.2 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side4.backgroundColor = [NSColor colorWithHue:0.2 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side4.borderWidth = 2.0;
side4.cornerRadius = 30.0;
side4.frame = layerRect;
side4.position = screenCenter;
//positioning
rotation = CATransform3DMakeRotation(M_PI/2, 0.0, 1.0, 0.0);
translation = CATransform3DMakeTranslation(size/-2, 0.0, size/-2);
side4.transform = CATransform3DConcat(rotation, translation);
[transformLayer addSublayer:side4];
//side5
CALayer *side5 = [CALayer layer];
side5.borderColor = [NSColor colorWithHue:0.8 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side5.backgroundColor = [NSColor colorWithHue:0.8 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side5.borderWidth = 2.0;
side5.cornerRadius = 30.0;
side5.frame = layerRect;
side5.position = screenCenter;
//positioning
rotation = CATransform3DMakeRotation(M_PI/2, 1.0, .0, 0.0);
translation = CATransform3DMakeTranslation(0.0, size/-2, size/-2);
side5.transform = CATransform3DConcat(rotation, translation);
[transformLayer addSublayer:side5];
//side6
CALayer *side6 = [CALayer layer];
side6.borderColor = [NSColor colorWithHue:0.0845 saturation:1.0 brightness:1.0 alpha:1.0].CGColor;
side6.backgroundColor = [NSColor colorWithHue:0.0845 saturation:1.0 brightness:1.0 alpha:0.8].CGColor;
side6.borderWidth = 2.0;
side6.cornerRadius = 30.0;
side6.frame = layerRect;
side6.position = screenCenter;
//positioning
rotation = CATransform3DMakeRotation(M_PI/2, 1.0, .0, 0.0);
translation = CATransform3DMakeTranslation(0.0, size/2, size/-2);
side6.transform = CATransform3DConcat(rotation, translation);
[transformLayer addSublayer:side6];
transformLayer.anchorPointZ = -size/2;
[cubeView setWantsLayer:YES];
[cubeView.layer addSublayer:transformLayer];
//animate
CGFloat perspective = -1.0/10000.0;
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
CATransform3D transform = CATransform3DIdentity;
transform.m34 = perspective;
transformAnimation.fromValue = [NSValue valueWithCATransform3D:transform];
transform.m34 = perspective;
transform = CATransform3DRotate(transform, DEGREES_TO_RADIANS(90) , 1, 0, 0);
transformAnimation.toValue = [NSValue valueWithCATransform3D:transform];
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transformAnimation.repeatCount = INFINITY;
transformAnimation.duration = 10.0;
[transformLayer addAnimation:transformAnimation forKey:@"RotateTheBox"];
[self sideAnimation:side1 transform:CATransform3DTranslate(CATransform3DRotate(side1.transform, DEGREES_TO_RADIANS(90) , 1, 0, 0), 0, size/2, size/2)];
[self sideAnimation:side3 transform:CATransform3DTranslate(CATransform3DRotate(side3.transform, DEGREES_TO_RADIANS(-90) , 1, 0, 0), 0, size/2, -size/2)];
[self sideAnimation:side2 transform:CATransform3DTranslate(CATransform3DRotate(side2.transform, DEGREES_TO_RADIANS(90) , 1, 0, 0), 0, size/2, size/2)];
[self sideAnimation:side4 transform:CATransform3DTranslate(CATransform3DRotate(side4.transform, DEGREES_TO_RADIANS(-90) , 1, 0, 0), 0, size/2, -size/2)];
[self sideAnimation:side6 transform:CATransform3DTranslate(side6.transform, 0, 0, size)];//lower cap
-(void)sideAnimation:(CALayer*)side transform:(CATransform3D)transform
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
transformAnimation.toValue = [NSValue valueWithCATransform3D:transform];
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transformAnimation.repeatCount = INFINITY;
transformAnimation.duration = 10.0;
[side addAnimation:transformAnimation forKey:@"rotateSide"];
【讨论】:
以上是关于沿锚点旋转 CATransformLayer的主要内容,如果未能解决你的问题,请参考以下文章