如何旋转包含UIBezierPath的CAShapeLayer?

时间:2012-12-04 07:09:11

标签: ios rotation calayer

  

可能重复:
  Rotate CGPath without changing its position

我搜索并测试了几个小时的代码,但我无法使用它。

我在随机位置添加一个任意UIBezierPath到CAShapeLayer,它被添加到视图中。我需要旋转路径,以便我可以处理设备旋转。我可以旋转图层而不是路径。我只需要旋转结果。

我已经有了通过缩放和转换来处理bezier路径转换的方法。它工作得很好,但现在我只需要向左或向右旋转90度。

有关如何执行此操作的任何建议吗?

基本代码:

UIBezierPath *path = <create arbitrary path>
CAShapeLayer *layer = [CAShapeLayer layer];
[self addPathToLayer:layer
             fromPath:path];

// I could get the center of the box but where is the box center for the view it is in?
// CGRect box = CGPathGetPathBoundingBox(path.CGPath);

// layer.anchorPoint = ? How to find the center of the box for the anchor point?

// Rotating here appears to rotate around 0,0 of the view
layer.transform = CATransform3DMakeRotation(DegreesToRadians(-90), 0.0, 0.0, 1.0);

我看到以下帖子: BezierPath Rotation in a UIView

我想我可以按原样旋转,然后将路径转换回原位。我只需要弄清楚翻译的价值是什么。

我还应该声明,在我尝试旋转之后,我看到的是图像在某处移动到屏幕外。我尝试旋转25度观察移动,并围绕视图的原点0 0旋转,这样如果我旋转90度,图像就会离屏。我在没有旋转设备的情况下运行这些测试 - 只是为了看旋转是如何工作的。

更新#1 - 12/4/2012:出于某些奇怪的原因,如果我将位置设置为一个值,我根据经验发现它会在旋转后将旋转的贝塞尔曲线路径移动到正确的位置:

layer.position = CGPointMake(280, 60);

这个值是从启动/停止应用程序并进行调整的猜测。我不知道为什么我需要调整旋转位置。锚点应位于图层的中心。但是,我确实发现即使设置了路径,CAShapeLayer的帧和位置都是ZERO,并且路径在视图中的位置也是正确的。当旋转+90时,280,60位置将路径移动到路径边界框的中心。如果我改变旋转值,我需要调整位置。我不应该手动调整。

我认为最后的办法是以某种方式将bezier路径转换为图像,然后添加它。我发现如果我将图层内容设置为图像,然后旋转,它会围绕其中心点旋转而不需要进行位置调整。设置路径不是这样。

UPDATE#2 12/4/2012 - 我尝试设置框架并摆弄,我把它放在如下的中心位置:

CGRect box = CGPathGetPathBoundingBox(path.CGPath);
CGRect rect = CGRectMake(0, 0, box.origin.x + (3.5 * box.size.width), box.origin.y + (3.5 * box.size.height));
layer.frame = rect;
layer.transform = CATransform3DMakeRotation(DegreesToRadians(90), 0.0, 0.0, 1.0);

为什么乘以3.5?我没有线索。我发现添加大小约为盒子大小3.5倍的盒子原点会将旋转的CAShapeLayer路径移动到大约应该的位置。

必须有更好的方法来做到这一点。这是比我之前的帖子更好的解决方案,因为帧大小不依赖于旋转角度。我只是不知道为什么需要将帧设置为我设置的值。我认为它应该是    CGRectMake(0,0,box.origin.x +(box.size.width / 2),box.origin.y +(box.size.height / 2));

但是,它会将图像向左移动太多。

我发现的另一个线索是,如果我设置[自我视图] .frame的框架(整个父视图的框架,即iPhone的屏幕),然后旋转,旋转点是中心的屏幕,路径/图像围绕此中心点轨道运行。这就是为什么我尝试将框架移动到路径中心的位置,以便它围绕盒子中心运行。

更新#3 12/4/2012 - 我尝试将图层渲染为图像。但是,看起来只是设置一个图层的路径并不会使它成为一个&#34;图像&#34;在图层中,因为它是空的

    CGRect box = CGPathGetPathBoundingBox(path.CGPath);
    layer.frame = box;

    UIImage *image = [ImageHelper imageFromLayer:layer]; // ImageHelper library I created  

    CAShapeLayer *newLayer = [CAShapeLayer layer];
    newLayer.frame = CGRectMake(box.origin.x, box.origin.y, image.size.width, image.size.height);
    newLayer.contents = (id) image.CGImage;

看起来,使用其路径设置旋转图层与简单地旋转贝塞尔曲线路径本身没有什么不同。我将回到旋转bezier路径,看看我是否可以摆弄位置元素或其他东西。我们必须解决这个问题。

目标:在最初创建的视图中围绕其中心点旋转UIBezierPath。

UPDATE#4 12/4/2012 - 我进行了一系列测试,测量翻译所需的值,以便将UIBezierPath放置在其先前的中心位置。

CGAffineTransform rotate = CGAffineTransformMakeRotation(DegreesToRadians(-15));
[path applyTransform:rotate];

// CGAffineTransform translate = CGAffineTransformMakeTranslation(-110, 70); // -45
CGAffineTransform translate = CGAffineTransformMakeTranslation(-52, -58); // -15
[path applyTransform:translate];

然而,x / y平移的比率不对应,因此我无法根据角度推断出所需的平移。看来&#39; CGAffineTransformMakeRotation&#39;使用一些任意的锚来进行旋转,此刻看起来可能是(viewWidth / 2,0)。我做得比实际需要的要困难得多。有一些我缺少的东西可以进行简单的旋转,以便保持中心点。我只需要&#34;旋转&#34;路径向左或向右90度。

更新#5 12/4/2012 - 运行其他测试后,似乎旋转UIBezierPath的锚点是绘制所有点的原点。在这种情况下,原点是0,0并且所有点都相对于该点。因此,它应用了一个旋转,旋转发生在原点周围,这就是为什么路径在-90上向右上移,在90上向左上移动。我需要以某种方式将旋转的锚点设置到中心,这样它&#34;旋转&#34;围绕中心,而不是原始的原点。在这一个问题上花了12个小时。

1 个答案:

答案 0 :(得分:5)

经过一些详细的分析和绘制纸上的边界框后,我发现我断言0,0的来源是正确的。

此问题的解决方案是将路径(基础矩阵)转换为原点,边界框的中心位于原点,旋转,然后将路径转换回原始位置。

以下是如何将UIBezierPath旋转90度:

CGAffineTransform translate = CGAffineTransformMakeTranslation(-1 * (box.origin.x + (box.size.width / 2)), -1 * (box.origin.y + (box.size.height / 2)));
[path applyTransform:translate];

CGAffineTransform rotate = CGAffineTransformMakeRotation(DegreesToRadians(90));
[path applyTransform:rotate];

translate = CGAffineTransformMakeTranslation((box.origin.x + (box.size.width / 2)), (box.origin.y + (box.size.height / 2)));
[path applyTransform:translate];

插入-90度以向另一个方向旋转。

当将设备从纵向旋转到横向时,可以使用此公式,反之亦然。

我仍然认为这不是理想的解决方案,但结果是我现在所需要的。

如果有人有更好的解决方案请发布。

更新12/7/2012 - 我发现了我认为最好的解决方案,并且非常简单,因为我会这样。我不是在贝塞尔曲线路径上使用旋转,平移和缩放方法,而是将点数组提取为CGPoint对象,并根据视图大小和方向根据需要缩放/平移它们。然后,我创建一个新的贝塞尔曲线路径并将图层设置为此路径。

结果是完美的缩放,平移,旋转。