web-dev-qa-db-fra.com

Comment faire des transformations sur un CALayer?

Avant d'écrire cette question, j'ai

Cependant, j'ai toujours du mal à comprendre comment effectuer des transformations de base sur une couche . Il a été difficile de trouver des explications et des exemples simples pour traduire, faire pivoter et mettre à l'échelle.

Aujourd'hui, j'ai finalement décidé de m'asseoir, de faire un projet de test et de les comprendre. Ma réponse est ci-dessous.

Remarques:

  • Je ne fais que Swift, mais si quelqu'un d'autre veut ajouter le code Objective-C, soyez mon invité.
  • À ce stade, je ne m'intéresse qu'à la compréhension des transformations 2D.
30
Suragch

Les bases

Il existe un certain nombre de transformations différentes que vous pouvez effectuer sur un calque, mais les

  • traduire (déplacer)
  • échelle
  • tourner

enter image description here

Pour effectuer des transformations sur un CALayer, vous définissez la propriété transform du calque sur un type CATransform3D. Par exemple, pour traduire un calque, vous feriez quelque chose comme ceci:

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

Le mot Make est utilisé dans le nom pour créer la transformation initiale: CATransform3D Make Translation. Les transformations suivantes qui sont appliquées omettent le Make. Voir, par exemple, cette rotation suivie d'une traduction:

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

Maintenant que nous avons la base de la façon de faire une transformation, regardons quelques exemples de comment faire chacun. Mais d'abord, je vais montrer comment j'ai configuré le projet au cas où vous voudriez aussi jouer avec.

Installer

Pour les exemples suivants, j'ai configuré une application à vue unique et ajouté un UIView avec un fond bleu clair au storyboard. J'ai connecté la vue au contrôleur de vue avec le code suivant:

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 ...


    }

} 

Il existe différents types de CALayer , mais j'ai choisi d'utiliser CATextLayer pour que les transformations soient plus claires visuellement.

Traduire

La transformation de translation déplace le calque. La syntaxe de base est

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

tx est le changement des coordonnées x, ty est le changement en y et tz est le changement en z.

Exemple

enter image description here

Dans iOS, l'origine du système de coordonnées est en haut à gauche, donc si nous voulions déplacer le calque de 90 points vers la droite et 50 points vers le bas, nous ferions ce qui suit:

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

Remarques

  • N'oubliez pas que vous pouvez coller ceci dans la méthode transformExample() dans le code de projet ci-dessus.
  • Puisque nous allons juste traiter deux dimensions ici, tz est réglé sur 0.
  • La ligne rouge dans l'image ci-dessus va du centre de l'emplacement d'origine au centre du nouvel emplacement. En effet, les transformations sont effectuées par rapport au point d'ancrage et le point d'ancrage est par défaut au centre du calque.

Échelle

La transformation d'échelle étire ou écrase le calque. La syntaxe de base est

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

sx, sy et sz sont les nombres par lesquels mettre à l'échelle (multiplier) les coordonnées x, y et z respectivement.

Exemple

enter image description here

Si nous voulions réduire de moitié la largeur et tripler la hauteur, nous ferions ce qui suit

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

Remarques

  • Comme nous ne travaillons qu'en deux dimensions, nous multiplions simplement les coordonnées z par 1,0 pour les laisser inchangées.
  • Le point rouge dans l'image ci-dessus représente le point d'ancrage. Remarquez comment la mise à l'échelle est effectuée par rapport au point d'ancrage. Autrement dit, tout est tendu vers ou loin du point d'ancrage.

Tourner

La transformation de rotation fait pivoter le calque autour du point d'ancrage (le centre du calque par défaut). La syntaxe de base est

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

angle est l'angle en radians que le calque doit faire pivoter et x, y et z sont les axes autour desquels tourner. La définition d'un axe sur 0 annule une rotation autour de cet axe particulier.

Exemple

enter image description here

Si nous voulions faire pivoter un calque de 30 degrés dans le sens des aiguilles d'une montre, nous procéderions comme suit:

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

Remarques

  • Puisque nous travaillons en deux dimensions, nous voulons seulement que le plan xy tourne autour de l'axe z. Ainsi, nous définissons x et y sur 0.0 Et définissons z sur 1.0.
  • Cela a fait pivoter le calque dans le sens horaire. Nous aurions pu tourner dans le sens antihoraire en définissant z sur -1.0.
  • Le point rouge indique l'emplacement du point d'ancrage. La rotation se fait autour du point d'ancrage.

Transformations multiples

Afin de combiner plusieurs transformations, nous pourrions utiliser la concatination comme celle-ci

CATransform3DConcat(a: CATransform3D, b: CATransform3D)

Cependant, nous ferons juste l'un après l'autre. La première transformation utilisera Make dans son nom. Les transformations suivantes n'utiliseront pas Make, mais elles prendront la transformation précédente comme paramètre.

Exemple

enter image description here

Cette fois, nous combinons les trois transformations précédentes.

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

Remarques

  • L'ordre dans lequel les transformations sont effectuées en matière.
  • Tout a été fait par rapport au point d'ancrage (point rouge).

Une note sur le point d'ancrage et la position

Nous avons fait toutes nos transformations ci-dessus sans changer le point d'ancrage. Parfois, il est toutefois nécessaire de le modifier, comme si vous souhaitez faire pivoter un autre point en plus du centre. Cependant, cela peut être un peu délicat.

Le point d'ancrage et la position sont tous deux au même endroit. Le point d'ancrage est exprimé sous la forme d'une unité du système de coordonnées de la couche (la valeur par défaut est 0.5, 0.5) Et la position est exprimée dans le système de coordonnées de la super couche. Ils peuvent être définis comme ceci

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

Si vous définissez uniquement le point d'ancrage sans modifier la position, le cadre change de sorte que la position soit au bon endroit. Ou plus précisément, le cadre est recalculé en fonction du nouveau point d'ancrage et de l'ancienne position. Cela donne généralement des résultats inattendus. Les deux articles suivants en ont une excellente discussion.

Voir également

98
Suragch