ios - 如何旋转包含UIBezierPath的CAShapeLayer?

标签 ios rotation calayer

Possible Duplicate:
Rotate CGPath without changing its position


我搜索并测试了各种代码几个小时,但无法正常工作。

我在CAShapeLayer的随机位置处添加了任意UIBezierPath,该对象已添加到视图中。我需要旋转路径,以便可以处理设备旋转。我可以旋转图层而不是路径。我只需要旋转结果。

我已经有了通过缩放和转换来处理贝塞尔曲线路径的方法。效果很好,但是现在我只需要向左或向右旋转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-2012年12月4日:出于某些奇怪的原因,如果我将位置设置为我凭经验发现的值,则旋转后将旋转的贝塞尔曲线路径移动到正确的位置:
layer.position = CGPointMake(280, 60);

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

我认为最后的解决方法是将贝塞尔曲线路径转换为图像,然后将其添加。我发现,如果将图层内容设置为图像,然后旋转,则它将绕其中心点旋转,而无需进行位置调整。设置路径并非如此。

更新#2 2012年12月4日-我尝试设置框架,并通过摆弄使它居中,如下所示:
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));

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

我发现的另一个线索是,如果我设置[self view] .frame的框架(整个父视图的框架,即iPhone的屏幕),然后旋转,则旋转点是屏幕的中心,该中心点周围的路径/图像轨道。这就是为什么我尝试将框架移动到路径的中心应位于框中心附近的原因。

更新#3 2012年12月4日-我尝试将图层渲染为图像。但是,似乎只设置图层的路径并不能使它成为图层中的“图像”,因为它是空的
    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;

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

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

更新#4 2012年12月4日-我进行了一系列测试,测量了转换所需的值,以便将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平移的比率不对应,因此我无法根据角度推断所需的平移。似乎“CGAffineTransformMakeRotation”使用放置了一些任意锚点进行旋转,此刻似乎是(viewWidth / 2,0)。我正在使这比需要做的难得多。我缺少进行简单的旋转以便保持中心点的功能。我只需要向左或向右90度“旋转”路径。

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

最佳答案

经过一些详细的分析并在纸上画出了边界框,我发现我的断言是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度即可向另一个方向旋转。

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

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

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

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

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

关于ios - 如何旋转包含UIBezierPath的CAShapeLayer? ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13697772/

相关文章:

ios - 如何在表格 View 单元格的顶部添加阴影?

c - C中矩形数组的二维旋转

c++ - 在 OpenCV 中使用旋转和平移矩阵

ios - 如何在 ios 中将纹理设置为 CALayer?

ios - 在触摸事件上识别 CALayer(将功能代码移植到 Swift)

c++ - 我怎样才能在 opengl 中旋转我的对象

iphone - 使用 NSSortDescriptor 时,您可以使用 NSPredicate 将获取的项目放在所有其他项目之前吗

ios - Swift:使用 `var` 会导致编译器警告,使用 `let` 会导致编译器错误?

ios - 我应该在 block 内使用哪个 NSAssertion?

ios - 在 iOS 应用程序的整个 Web View 中保留登录凭据(快速)