如何在CALayer上进行转换?

在写这个问题之前,我已经

  • 有Affine转换观点的经验
  • 阅读Quartz 2D Programming Guide中的Transforms文档
  • 看到这个详细的CALayer教程
  • 从Github下载并运行LayerPlayer项目

不过,我仍然无法理解如何在图层上进行基本的变换。 寻找翻译,旋转和缩放的解释和简单的例子已经很困难。

今天,我终于决定坐下来,做一个testing项目,并把它们弄清楚。 我的答案在下面。

笔记:

  • 我只做Swift,但如果别人想要添加Objective-C代码,请成为我的客人。
  • 在这一点上,我只关心理解二维变换。

基本

在图层上可以进行多种不同的转换,但基本的转换是

  • 翻译(移动)
  • 规模
  • 回转

在这里输入图像说明

要在CALayer上进行转换,可以将图层的transform属性设置为CATransform3Dtypes。 例如,要翻译一个图层,你可以这样做:

 myLayer.transform = CATransform3DMakeTranslation(20, 30, 0) 

Make这个词用于创build初始转换的名称:CATransform3D Make Translation。 随后应用的转换省略了Make 。 例如,请看这个旋转,然后翻译:

 let rotation = CATransform3DMakeRotation(CGFloat.pi * 30.0 / 180.0, 20, 20, 0) myLayer.transform = CATransform3DTranslate(rotation, 20, 30, 0) 

现在我们已经有了如何进行转换的基础,接下来我们来看看如何进行转换的一些例子。 但是,首先,我将展示如何设置该项目,以防止您想要使用它。

build立

对于下面的例子,我设置了一个单一的视图应用程序,并添加了一个淡蓝色背景的UIView到故事板。 我用以下代码将视图连接到视图控制器:

 import UIKit class ViewController: UIViewController { var myLayer = CATextLayer() @IBOutlet weak var myView: UIView! override func viewDidLoad() { super.viewDidLoad() // setup the sublayer addSubLayer() // do the transform transformExample() } func addSubLayer() { myLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 40) myLayer.backgroundColor = UIColor.blue.cgColor myLayer.string = "Hello" myView.layer.addSublayer(myLayer) } //******** Replace this function with the examples below ******** func transformExample() { // add transform code here ... } } 

CALayer有很多不同的types ,但是我select了使用CATextLayer以便视觉更清晰。

翻译

翻译变换移动图层。 基本的语法是

 CATransform3DMakeTranslation(tx: CGFloat, ty: CGFloat, tz: CGFloat) 

其中tx是x坐标的变化, ty是y的变化, tz是z的变化。

在这里输入图像说明

在iOS中,坐标系的原点位于左上方,所以如果我们想要将图层90点向右移动50点,我们将执行以下操作:

 myLayer.transform = CATransform3DMakeTranslation(90, 50, 0) 

笔记

  • 请记住,您可以将其粘贴到上述项目代码中的transformExample()方法中。
  • 既然我们要在这里处理两个维度, tz被设置为0
  • 上图中的红线从原始位置的中心到新位置的中心。 这是因为转换是相对于锚点完成的,并且默认情况下锚点位于图层的中心。

规模

缩放变换拉伸或挤压图层。 基本的语法是

 CATransform3DMakeScale(sx: CGFloat, sy: CGFloat, sz: CGFloat) 

其中sxsysz分别是对x,y和z坐标进行缩放(乘)的数字。

在这里输入图像说明

如果我们想要宽度的一半和高度的三倍,我们会做以下的事情

 myLayer.transform = CATransform3DMakeScale(0.5, 3.0, 1.0) 

笔记

  • 由于我们只是在两个维度上工作,所以我们只需将z坐标乘以1.0就可以不受影响。
  • 上图中的红点表示锚点。 请注意缩放是如何与锚点相关的。 也就是说,一切都要么拉向或远离定位点。

旋转

旋转变换旋转锚点周围的图层(默认为图层的中心)。 基本的语法是

 CATransform3DMakeRotation(angle: CGFloat, x: CGFloat, y: CGFloat, z: CGFloat) 

其中angle是以弧度表示的层应该旋转的angular度,而xyz是围绕其旋转的轴。 将坐标轴设置为0将取消围绕该特定坐标轴的旋转。

在这里输入图像说明

如果我们想要顺时针旋转一层30度,我们可以这样做:

 let degrees = 30.0 let radians = CGFloat(degrees * Double.pi / 180) myLayer.transform = CATransform3DMakeRotation(radians, 0.0, 0.0, 1.0) 

笔记

  • 由于我们在两个维度上工作,我们只希望xy平面围绕z轴旋转。 因此,我们将xy设置为0.0 ,并将z设置为1.0
  • 这顺时针方向旋转该层。 我们可以通过将z设置为-1.0来逆时针旋转。
  • 红点显示了锚点的位置。 旋转是在锚点周围完成的。

多重转换

为了组合多个转换,我们可以像这样使用连接

 CATransform3DConcat(a: CATransform3D, b: CATransform3D) 

但是,我们只会一个接一个地做。 第一个转换将使用Make作为其名称。 下面的转换不会使用Make ,但是它们会将之前的转换作为参数。

在这里输入图像说明

这一次,我们结合了以前所有的三个转换。

 let degrees = 30.0 let radians = CGFloat(degrees * Double.pi / 180) // translate var transform = CATransform3DMakeTranslation(90, 50, 0) // rotate transform = CATransform3DRotate(transform, radians, 0.0, 0.0, 1.0) // scale transform = CATransform3DScale(transform, 0.5, 3.0, 1.0) // apply the transforms myLayer.transform = transform 

笔记

  • 事情的转换完成的顺序。
  • 一切都是根据锚点(红点)完成的。

关于锚点和位置的一个注记

我们在不改变锚点的情况下完成了上面的所有转换。 有时候有必要改变它,但是,如果你想围绕除了中心之外的其他点旋转。 但是,这可能有点棘手。

定位点和位置都在同一个地方。 锚点表示为图层坐标系统的单位(默认值为0.5,0.5),位置表示在上层坐标系统中。 他们可以像这样设置

 myLayer.anchorPoint = CGPoint(x: 0.0, y: 1.0) myLayer.position = CGPoint(x: 50, y: 50) 

如果您只在不改变位置的情况下设置定位点,则框架会发生变化,以使位置位于正确的位置。 或者更确切地说,基于新的锚点和旧的位置重新计算框架。 这通常会带来意想不到的结 以下两篇文章有很好的讨论。

  • 关于anchorPoint
  • 翻译旋转翻译?

也可以看看

  • 边框,圆angular和CALayer上的阴影
  • 使用具有贝塞尔path的边框作为图层