Як застосувати перегляд перспективи до UIView?


199

Я хочу виконати перспективну трансформацію на UIView (наприклад, видно в coverflow)

Хтось знає, чи можливо це?

Я досліджував, використовуючи CALayerі прагнув усі подкасти прагматичного програміста Core Animation, але мені все одно не зрозуміло, як створити подібну трансформацію на iPhone.

Будь-яка допомога, покажчики чи приклади фрагментів коду були б дуже вдячні!


Я не впевнений, чи підходить це вам чи ні, але коли я роблю анімацію, я виявив, що m14 краще для мене. Для довідки :)
b123400

Дякую! - які значення ви даєте цьому?
Нік Картрайт

1
Встановивши m14, ви насправді перекошуєте фрустум виду на осі X дивно. Математика цілком справедлива, але це зробить речі дещо заплутаними в загальному випадку.
пухнастий

Дуже гарну статтю про трансформацію та перспективу CALayer 3D, включаючи ретельне пояснення поля m34, можна знайти в цій чудовій статті: core-animation-3d-model
Markus

Відповіді:


329

Як сказав Бен, вам потрібно буде працювати з UIView'sшаром, використовуючи a CATransform3Dдля виконання layer's rotation. Хитрість , щоб отримати перспективну роботу, так як описано тут , є безпосередньо доступ до одного з матриці cellsз CATransform3D(m34). Математика матриці ніколи не була моєю річчю, тому я не можу точно пояснити, чому це працює, але це так. Вам потрібно буде встановити це значення на від’ємну частку для початкового перетворення, а потім застосувати до цього ваші перетворення обертання шару. Ви також можете зробити наступне:

Ціль-С

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;

Швидкий 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's CALayer. Якщо у вас немає підшарів, не переживайте про це. Я використовую sublayerTransform у своєму прикладі просто тому, що CALayersв одному шарі, який я обертаю, є два .


1
Спасибі Бред - ти зірка. PS: Вибачте за пізнє позначення вашої чудової відповіді! Нік.
Нік Картрайт

Це добре працює для мене, за винятком того, що я, здається, втрачаю половину свого іміджу (уздовж вертикального поділу) - іноді LHS, іноді RHS.
iPadDeveloper2011

18
@ iPadDeveloper2011 - Коефіцієнти є, ви намагаєтеся повернути вигляд або шар, коли на одній площині є інший непрозорий вид або шар. Половина вашого перегляду або шару, які проектуються далеко від екрана, буде розташована нижче цього іншого виду і, таким чином, буде прихована. Ви можете або змінити порядок ієрархії перегляду, щоб запобігти цьому, або скористатися властивістю zPosition, щоб перемістити ваш вигляд переднього плану досить високо над тим, який його відрізає.
Бред Ларсон

26
FYI, причина, що клітинка m34 впливає на перетворення в перспективі, полягає в тому, що клітина в матриці впливає на те, як значення Z-світового простору відображається на значення W-простору кліпу (яке використовується для перспективного прогнозування). Прочитайте на однорідних матрицях перетворення для отримання додаткової інформації.
пухнастий

2
@uerceg - Ви хочете задати це як окреме запитання, бажано із зображеннями, які ілюструють те, що відбувається і що ви хочете статися.
Бред Ларсон

7

Можна використовувати лише перетворення Core Graphics (лише для Quartz, 2D), безпосередньо застосовані до властивості перетворення UIView. Щоб отримати ефекти в потоці покриття, вам доведеться використовувати CATransform3D, які застосовуються в тривимірному просторі, і таким чином можна надати вам перспективний вигляд. Можна застосовувати лише CATransform3Ds до шарів, а не до представлень, тому для цього вам доведеться перейти на шари.

Перевірте зразок "CovertFlow", що постачається з Xcode. Це лише для Mac (тобто не для iPhone), але багато концепцій добре передаються.


Я шукаю цей зразок покриття в / Developer / Examples, без успіху, де його можна знайти?
Олексій

Це насправді "CovertFlow", і це в / Developer / Examples / Quartz / Core Animation / "
Ben Gottlieb

3

Щоб додати відповідь Бреда та навести конкретний приклад, я запозичую свою власну відповідь в іншій публікації на подібну тему. У своїй відповіді я створив простий майданчик Swift, який ви можете завантажити та грати , де я демонструю, як створити перспективні ефекти UIView за допомогою простої ієрархії шарів, і я показую різні результати між використанням transformта sublayerTransform. Перевір.

Ось кілька зображень із поста:

Параметр .sublayerTransform

.трансформаційний варіант


Код слід розміщувати як текст. Читати код на зображенні дійсно важко. Плюс код на малюнку не можна посилатись, копіювати чи шукати.
rmaddy

@rmaddy, у мене є відповідність коду у посиланні Bitbucket.
HuaTham

З часом посилання виходять поганими. Завжди найкраще вставити важливий код як текст прямо у відповідь.
rmaddy

-1

Ви можете отримати точний ефект каруселі за допомогою 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
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.