【问题标题】:How to do transforms on a CALayer?如何在 CALayer 上进行转换?
【发布时间】:2016-03-30 01:52:22
【问题描述】:

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

但是,我仍然无法理解如何在 layer 上进行基本转换。很难找到平移、旋转和缩放的解释和简单示例。

今天我终于决定坐下来,做一个测试项目,然后弄清楚。我的答案如下。

注意事项:

  • 我只做 Swift,但如果其他人想添加 Objective-C 代码,请做我的客人。
  • 此时我只关心理解 2D 变换。

【问题讨论】:

    标签: ios swift transform calayer


    【解决方案1】:

    基础知识

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

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

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

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

    Make 一词用于创建初始变换的名称:CATransform3DMakeTranslation。应用的后续转换省略Make。例如,看这个旋转后跟一个平移:

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

    现在我们已经掌握了如何进行转换的基础,让我们看一些如何进行转换的示例。不过,首先,我将展示我是如何设置项目的,以防你也想玩弄它。

    设置

    对于以下示例,我设置了一个单视图应用程序,并将带有浅蓝色背景的 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 ...
            
            
        }
    
    } 
    

    There are many different kinds of CALayer,但我选择使用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 是层应该旋转的弧度角,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)
    

    如果您只设置锚点而不更改位置,则框架会更改,以便位置在正确的位置。或者更准确地说,根据新锚点和旧位置重新计算帧。这通常会产生意想不到的结果。以下两篇文章对此进行了很好的讨论。

    另见

    【讨论】:

    • 精彩的解释。实现这一点非常有用。缩放图层时如何解决文本缩小/扩展问题?
    • @Vijay,我不太清楚你的意思。最好为此提出一个新问题。
    • 嗨@Suragch,你不知道为什么在缩放CALayer opbject 时,它的中心在移动?它应该保持不变。
    • @Shamsiddin,我已经有一段时间没有做这个了,但据我所知,中心确实保持不变。在上面的缩放示例中确实如此。
    • @Suragch,你在轮换状态下做什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多