Как применить преобразование перспективы к UIView?
Я хочу выполнить преобразование перспективы на UIView (например, видимое в обложке)
Знает ли кто-нибудь, возможно ли это?
Я исследовал с помощью CALayer
и пропустил все прагматические программные подкасты Core Animation, но я все еще не понимаю, как создать такой тип преобразования на iPhone.
Любые справки, указатели или фрагменты кода кода будут действительно оценены!
Ответы
Ответ 1
Как сказал Бен, вам нужно будет работать со слоем UIView
, используя CATransform3D
для выполнения layer
rotation
. Хитрость для получения перспективной работы, как описано здесь, состоит в том, чтобы получить прямой доступ к одной из матриц cells
CATransform3D
(m34). Математическая математика никогда не была моей вещью, поэтому я не могу точно объяснить, почему это работает, но это работает. Вам нужно будет установить это значение в отрицательную дробь для вашего первоначального преобразования, а затем применить к нему преобразования вращения слоя. Вы также должны быть в состоянии сделать следующее:
Objective-C
UIView *myView = [[self subviews] objectAtIndex:0];
CALayer *layer = myView.layer;
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / -500;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 45.0f * M_PI / 180.0f, 0.0f, 1.0f, 0.0f);
layer.transform = rotationAndPerspectiveTransform;
Swift 5.0
if let myView = self.subviews.first {
let layer = myView.layer
var rotationAndPerspectiveTransform = CATransform3DIdentity
rotationAndPerspectiveTransform.m34 = 1.0 / -500
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 45.0 * .pi / 180.0, 0.0, 1.0, 0.0)
layer.transform = rotationAndPerspectiveTransform
}
который перестраивает преобразование слоя с нуля для каждого поворота.
Полный пример этого (с кодом) можно найти здесь, где я реализовал ротацию и масштабирование на основе касания для пары CALayers
, основываясь на примере Билла Дадни. Самая новая версия программы, в самом низу страницы, реализует такую перспективную операцию. Код должен быть достаточно простым для чтения.
sublayerTransform
, на который вы ссылаетесь в своем ответе, является преобразованием, которое применяется к подуровням вашего UIView
CALayer
. Если у вас нет подслоев, не беспокойтесь об этом. Я использую sublayerTransform в моем примере просто потому, что в одном вращаемом слое содержатся два CALayers
.
Ответ 2
Очень хорошая статья о 3D-преобразовании CALayer и перспективах, включая подробное объяснение поля m34, можно найти в этой замечательной статье:
core-animation-3d-model
Ответ 3
Вы можете использовать преобразования Core Graphics (Quartz, 2D only) напрямую, применяемые к свойству преобразования UIView. Чтобы получить эффекты в потолочном покрытии, вам придется использовать CATransform3D, которые применяются в трехмерном пространстве, и поэтому могут дать вам перспективный вид. Вы можете применять CATransform3D только к слоям, а не к представлениям, поэтому вам придется переключаться на слои для этого.
Проверьте образец "CovertFlow", который поставляется с Xcode. Это mac-only (то есть не для iPhone), но многие концепции хорошо переносятся.
Ответ 4
Чтобы добавить к ответу Брэда и привести конкретный пример, я заимствую свой ответ в другом посте на аналогичную тему. В своем ответе я создал простую игровую площадку Swift, с которой вы можете загружать и играть, где я демонстрирую, как создавать эффекты перспективы UIView с простой иерархией слоев, и я показываю разные результаты между использованием transform
и sublayerTransform
. Проверьте это.
Вот некоторые изображения из поста:
Ответ 5
Вы можете получить точный эффект Карусели, используя iCarousel SDK.
Вы можете получить мгновенный эффект Cover Flow на iOS с помощью великолепной и бесплатной библиотеки iCarousel. Вы можете скачать его с https://github.com/nicklockwood/iCarousel и довольно легко добавить в свой проект Xcode, добавив соединительный заголовок (он написан на Objective-C).
Если вы ранее не добавляли код Objective-C в проект Swift, выполните следующие действия:
- Скачайте iCarousel и распакуйте его
- Перейдите в разархивированную папку, откройте ее подпапку iCarousel, затем выберите iCarousel.h и iCarousel.m и перетащите их в навигацию проекта - на левую панель в Xcode. Чуть ниже Info.plist в порядке.
- Установите флажок "Копировать элементы при необходимости", затем нажмите "Готово".
- Xcode предложит вам сообщение "Хотите настроить заголовок моста Objective-C?" Нажмите "Создать заголовок моста". В вашем проекте вы увидите новый файл с именем YourProjectName-Bridging-Header.h.
- Добавьте эту строку в файл: #import "iCarousel.h"
- Как только вы добавили iCarousel в свой проект, вы можете начать его использовать.
- Убедитесь, что вы соответствуете протоколам iCarouselDelegate и iCarouselDataSource.
Образец кода Swift 3:
override func viewDidLoad() {
super.viewDidLoad()
let carousel = iCarousel(frame: CGRect(x: 0, y: 0, width: 300, height: 200))
carousel.dataSource = self
carousel.type = .coverFlow
view.addSubview(carousel)
}
func numberOfItems(in carousel: iCarousel) -> Int {
return 10
}
func carousel(_ carousel: iCarousel, viewForItemAt index: Int, reusing view: UIView?) -> UIView {
let imageView: UIImageView
if view != nil {
imageView = view as! UIImageView
} else {
imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 128, height: 128))
}
imageView.image = UIImage(named: "example")
return imageView
}