Как сделать преобразования на CALayer?

Моим решением является создание настраиваемого контроллера представлений с настраиваемой модальной презентацией на основе иерархии дочерних элементов-контроллеров.

Мои предложения для анимации:

animateWithDuration:(animated ? 0.6 : 0.0)
                      delay:0.0
     usingSpringWithDamping:1.f
      initialSpringVelocity:0.6f
                    options:UIViewAnimationOptionCurveEaseOut

Он будет выглядеть точно так же, как анимация модального представления по умолчанию в iOS7 / 8.

29
задан Community 23 May 2017 в 12:10
поделиться

1 ответ

Основы

Существует несколько различных преобразований, которые вы можете выполнять на слое, но основными являются

  • translate (move)
  • scale
  • rotate

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, чтобы преобразования будут более ясными визуально.

Translate

Преобразование перевода перемещает слой. Основной синтаксис:

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.
  • Красная линия на изображении выше идет от центра исходного местоположения к центру нового местоположения. Это связано с тем, что преобразования выполняются относительно точки привязки, а точка привязки по умолчанию находится в центре слоя.

Scale

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

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, чтобы оставить их без изменений.
  • Красная точка на изображении выше представляет точку привязки. Обратите внимание на то, как масштабирование делается по отношению к точке привязки. То есть все либо растягивается в направлении, либо от точки привязки.

Rotate

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

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)

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

См. Также

95
ответ дан Suragch 23 May 2017 в 12:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: