如何在CALayer上进行转换?

Sur*_*gch 31 transform calayer ios swift

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

但是,我仍然无法理解如何在图层上进行基本变换.寻找翻译,旋转和缩放的解释和简单示例一直很困难.

今天我终于决定坐下来,做一个测试项目,然后把它们搞清楚.我的答案如下.

笔记:

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

Sur*_*gch 102

基本

您可以在一个图层上执行许多不同的变换,但基本的变换是

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

在此输入图像描述

要对a进行转换CALayer,请将图层的transform属性设置为CATransform3D类型.例如,要翻译图层,您可以执行以下操作:

myLayer.transform = CATransform3DMakeTranslation(20, 30, 0)
Run Code Online (Sandbox Code Playgroud)

Make名称用于创建初始变换的名称:CATransform3D Make Translation.应用的后续转换省略了Make.例如,请参阅此轮换后跟翻译:

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

既然我们已经有了如何进行变换的基础,那么让我们看看如何做每个变换的一些例子.首先,我将展示如何设置项目,以防您想要玩它.

建立

对于以下示例,我设置了单视图应用程序,并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 ...


    }

} 
Run Code Online (Sandbox Code Playgroud)

有许多不同的类型CALayer,但我选择使用CATextLayer以便变换在视觉上更清晰.

翻译

平移变换移动图层.基本语法是

CATransform3DMakeTranslation(tx: CGFloat, ty: CGFloat, tz: CGFloat)
Run Code Online (Sandbox Code Playgroud)

txx坐标的变化在哪里,ty是y tz的变化,是z的变化.

在此输入图像描述

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

myLayer.transform = CATransform3DMakeTranslation(90, 50, 0)
Run Code Online (Sandbox Code Playgroud)

笔记

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

规模

缩放变换拉伸或取消该层.基本语法是

CATransform3DMakeScale(sx: CGFloat, sy: CGFloat, sz: CGFloat)
Run Code Online (Sandbox Code Playgroud)

其中sx,sysz是分别缩放(乘)x,y和z坐标的数字.

在此输入图像描述

如果我们想要宽度的一半和高度的三倍,我们将执行以下操作

myLayer.transform = CATransform3DMakeScale(0.5, 3.0, 1.0)
Run Code Online (Sandbox Code Playgroud)

笔记

  • 由于我们只是在两个维度上工作,我们只需将z坐标乘以1.0即可使它们不受影响.
  • 上图中的红点代表锚点.注意如何相对于锚点完成缩放.也就是说,一切都朝向或远离锚点拉伸.

旋转

旋转变换围绕锚点旋转图层(默认情况下为图层的中心).基本语法是

CATransform3DMakeRotation(angle: CGFloat, x: CGFloat, y: CGFloat, z: CGFloat)
Run Code Online (Sandbox Code Playgroud)

其中angle是在弧度的角度,该层应该旋转和x,y以及z是哪些以旋转轴.将轴设置为0可取消围绕该特定轴的旋转.

在此输入图像描述

如果我们想要将图层顺时针旋转30度,我们将执行以下操作:

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

笔记

  • 由于我们在两个维度上工作,我们只希望xy平面围绕z轴旋转.因此,我们设定xy0.0和设置z1.0.
  • 这使层顺时针旋转.我们可以通过设置z为逆时针旋转-1.0.
  • 红点表示锚点的位置.围绕锚点完成旋转.

多次转换

为了组合多个变换,我们可以像这样使用concatination

CATransform3DConcat(a: CATransform3D, b: CATransform3D)
Run Code Online (Sandbox Code Playgroud)

但是,我们将一个接一个地做.第一个转换将使用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
Run Code Online (Sandbox Code Playgroud)

笔记

  • 变换在事务中完成的顺序.
  • 一切都是关于锚点(红点)完成的.

关于锚点和位置的注记

我们在不改变锚点的情况下完成了上述所有变换.有时候有必要改变它,就像你想要围绕中心以外的其他点旋转一样.但是,这可能有点棘手.

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

myLayer.anchorPoint = CGPoint(x: 0.0, y: 1.0)
myLayer.position = CGPoint(x: 50, y: 50)
Run Code Online (Sandbox Code Playgroud)

如果仅设置锚点而不更改位置,则框架会发生变化,以使位置位于正确的位置.或者更确切地说,基于新的锚点和旧位置重新计算框架.这通常会产生意外结果.以下两篇文章对此进行了很好的讨论.

也可以看看

  • 精彩的解释。实现这一点非常有用。如何在缩放图层时修复文本缩小/扩展问题? (2认同)