Как сделать трансляции на CALayer?

Прежде чем писать этот вопрос, я

Однако мне все еще трудно понять, как делать базовые преобразования на уровне. Найти объяснения и простые примеры для перевода, поворота и масштабирования было сложно.

Сегодня я, наконец, решил сесть, сделать тестовый проект и выяснить их. Мой ответ ниже.

Примечания:

  • Я только делаю Swift, но если кто-то хочет добавить код Objective-C, будьте моим гостем.
  • В этот момент меня интересует только понимание двумерных преобразований.

Ответ 1

основы

Есть несколько различных преобразований, которые вы можете сделать на слое, но основные из них:

  • перевести (переместить)
  • масштаб
  • вращаться

enter image description here

Для преобразования на более CALayer, вы установите слой transform недвижимости CATransform3D типа. Например, чтобы перевести слой, вы должны сделать что-то вроде этого:

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

Слово Make используется в имени для создания исходного преобразования: CATransform3D Make Translation. Последующие преобразования, которые применяются, опускают Make. Посмотрите, например, это вращение с последующим переводом:

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

Теперь, когда у нас есть основы того, как сделать преобразование, давайте рассмотрим несколько примеров того, как это сделать. Однако сначала я покажу, как настроить проект на случай, если вы тоже захотите поиграть с ним.

Настроить

Для следующих примеров я настроил приложение Single View и добавил в 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, но я решил использовать CATextLayer чтобы преобразования были более четкими визуально.

Переведите

Трансляционное преобразование перемещает слой. Основной синтаксис

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

где tx - изменение координат x, ty - изменение y, а tz - изменение z.

пример

enter image description here

В iOS источник системы координат находится в верхнем левом углу, поэтому, если мы хотим переместить слой на 90 пунктов вправо и на 50 пунктов вниз, мы сделаем следующее:

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

Заметки

  • Помните, что вы можете вставить это в метод transformExample() в приведенном выше коде проекта.
  • Так как мы собираемся здесь иметь дело с двумя измерениями, tz установлен в 0.
  • Красная линия на изображении выше идет от центра исходного местоположения к центру нового местоположения. Это потому, что преобразования выполняются относительно точки привязки, а точка привязки по умолчанию находится в центре слоя.

Масштаб

Преобразование масштаба растягивает или сжимает слой. Основной синтаксис

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

где sx, sy и sz - числа, на которые можно масштабировать (умножать) координаты x, y и z соответственно.

пример

enter image description here

Если бы мы хотели вдвое уменьшить ширину и утроить высоту, мы бы сделали следующее

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

Заметки

  • Поскольку мы работаем только в двух измерениях, мы просто умножаем координаты z на 1,0, чтобы оставить их без изменений.
  • Красная точка на изображении выше представляет точку привязки. Обратите внимание на то, как масштабирование делается по отношению к точке привязки. То есть все либо растягивается в направлении, либо от точки привязки.

Поворот

Преобразование поворота поворачивает слой вокруг опорной точки (центр слоя по умолчанию). Основной синтаксис

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

где angle - это угол в радианах, что слой должен вращаться, а x, y и z - оси, вокруг которых вращается. Установка оси в 0 отменяет вращение вокруг этой конкретной оси.

пример

enter image description here

Если бы мы хотели повернуть слой по часовой стрелке на 30 градусов, мы бы сделали следующее:

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

Заметки

  • Поскольку мы работаем в двух измерениях, мы хотим, чтобы плоскость xy вращалась вокруг оси z. Таким образом, мы устанавливаем x и y в 0.0 и устанавливаем z в 1.0.
  • Это повернуло слой по часовой стрелке. Мы могли бы повернуть против часовой стрелки, установив z на -1.0.
  • Красная точка показывает, где находится точка привязки. Вращение осуществляется вокруг точки привязки.

Несколько преобразований

Чтобы объединить несколько преобразований, мы могли бы использовать конкатенацию, как это

CATransform3DConcat(a: CATransform3D, b: CATransform3D)

Однако мы будем просто делать одно за другим. Первое преобразование будет использовать Make в своем имени. Следующие преобразования не будут использовать Make, но они будут принимать предыдущее преобразование в качестве параметра.

пример

enter image description here

На этот раз мы объединяем все три предыдущих преобразования.

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)

Если вы устанавливаете только опорную точку, не меняя положение, то рамка изменится так, что положение будет в правильном месте. Точнее, кадр пересчитывается на основе новой точки привязки и старой позиции. Это обычно дает неожиданные результаты. Следующие две статьи отлично обсуждают это.

Смотрите также