ios 如何将透视变换应用于 UIView?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/347721/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:25:56  来源:igfitidea点击:

How do I apply a perspective transform to a UIView?

ioscocoa-touchuiviewcore-animationcalayer

提问by Nick Cartwright

I'm looking to perform a perspective transform on a UIView (such as seen in coverflow)

我希望在 UIView 上执行透视变换(例如在coverflow中看到的)

Does anyonew know if this is possible?

有谁知道这是否可能?

I've investigated using CALayerand have run through all the pragmatic programmer Core Animation podcasts, but I'm still no clearer on how to create this kind of transform on an iPhone.

我已经调查CALayer并浏览了所有实用的程序员 Core Animation 播客,但我仍然不清楚如何在 iPhone 上创建这种转换。

Any help, pointers or example code snippets would be really appreciated!

任何帮助、指针或示例代码片段将不胜感激!

回答by Brad Larson

As Ben said, you'll need to work with the UIView'slayer, using a CATransform3Dto perform the layer'srotation. The trick to get perspective working, as described here, is to directly access one of the matrix cellsof the CATransform3D(m34). Matrix math has never been my thing, so I can't explain exactly why this works, but it does. You'll need to set this value to a negative fraction for your initial transform, then apply your layer rotation transforms to that. You should also be able to do the following:

正如 Ben 所说,您需要使用UIView's图层,使用 aCATransform3D来执行layer'srotation. 如此处所述,使透视工作的技巧是直接访问(m34)的矩阵cells之一CATransform3D。矩阵数学从来不是我的事,所以我无法确切解释为什么会这样,但确实如此。您需要将此值设置为初始变换的负分数,然后将图层旋转变换应用于该值。您还应该能够执行以下操作:

Objective-C

目标-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

斯威夫特 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
}

which rebuilds the layer transform from scratch for each rotation.

它为每次旋转从头开始重建图层变换。

A full example of this (with code) can be found here, where I've implemented touch-based rotation and scaling on a couple of CALayers, based on an example by Bill Dudney. The newest version of the program, at the very bottom of the page, implements this kind of perspective operation. The code should be reasonably simple to read.

一个完整的例子(带代码)可以在这里找到,我已经基于CALayersBill Dudney 的一个例子在几个 上实现了基于触摸的旋转和缩放。最新版本的程序,在页面的最底部,实现了这种透视操作。代码应该相当简单易读。

The sublayerTransformyou refer to in your response is a transform that is applied to the sublayers of your UIView'sCALayer. If you don't have any sublayers, don't worry about it. I use the sublayerTransform in my example simply because there are two CALayerscontained within the one layer that I'm rotating.

sublayerTransform你指的是你的反应是一个转换,应用到你的子层UIView'sCALayer。如果您没有任何子层,请不要担心。我在示例中使用 sublayerTransform 只是因为CALayers在我旋转的一层中包含两个。

回答by Ben Gottlieb

You can only use Core Graphics?(Quartz, 2D only) transforms directly applied to a UIView's transform property. To get the effects in coverflow, you'll have to use CATransform3D, which are applied in 3-D space, and so can give you the perspective view you want. You can only apply CATransform3Ds to layers, not views, so you're going to have to switch to layers for this.

您只能使用直接应用于 UIView 的转换属性的核心图形?(仅限石英,2D)转换。要在 Coverflow 中获得效果,您必须使用 CATransform3D,它应用于 3-D 空间,因此可以为您提供所需的透视图。您只能将 CATransform3D 应用于图层,而不是视图,因此您将不得不为此切换到图层。

Check out the "CovertFlow" sample that comes with Xcode. It's mac-only (ie not for iPhone), but a lot of the concepts transfer well.

查看 Xcode 附带的“CovertFlow”示例。它仅适用于 mac(即不适用于 iPhone),但很多概念都可以很好地传递。

回答by HuaTham

To add to Brad's answer and to provide a concrete example, I borrow from my own answerin another post on a similar topic. In my answer, I created a simple Swift playground that you can download and play with, where I demonstrate how to create perspective effects of a UIView with a simple hierarchy of layers, and I show different results between using transformand sublayerTransform. Check it out.

为了补充布拉德的答案并提供一个具体的例子,我在另一篇关于类似主题的帖子中借用了我自己的答案。在我的回答中,我创建了一个简单的 Swift 游乐场,您可以下载并使用它,我在其中演示了如何使用简单的图层层次结构创建 UIView 的透视效果,并展示了使用transform和之间的不同结果sublayerTransform。一探究竟。

Here are some of the images from the post:

以下是帖子中的一些图片:

.sublayerTransform option

.sublayerTransform 选项

.transform option

.transform 选项

回答by Tech

You can get accurate Carousel effect using iCarousel SDK.

您可以使用 iCarousel SDK 获得准确的 Carousel 效果。

You can get an instant Cover Flow effect on iOS by using the marvelous and free iCarousel library. You can download it from https://github.com/nicklockwood/iCarouseland drop it into your Xcode project fairly easily by adding a bridging header (it's written in Objective-C).

您可以使用出色且免费的 iCarousel 库在 iOS 上获得即时 Cover Flow 效果。您可以从https://github.com/nicklockwood/iCarousel下载它,并通过添加桥接头(它是用 Objective-C 编写的)轻松地将其放入您的 Xcode 项目中。

If you haven't added Objective-C code to a Swift project before, follow these steps:

如果您之前没有将 Objective-C 代码添加到 Swift 项目,请按照以下步骤操作:

  • Download iCarousel and unzip it
  • Go into the folder you unzipped, open its iCarousel subfolder, then select iCarousel.h and iCarousel.m and drag them into your project navigation – that's the left pane in Xcode. Just below Info.plist is fine.
  • Check "Copy items if needed" then click Finish.
  • Xcode will prompt you with the message "Would you like to configure an Objective-C bridging header?" Click "Create Bridging Header" You should see a new file in your project, named YourProjectName-Bridging-Header.h.
  • Add this line to the file: #import "iCarousel.h"
  • Once you've added iCarousel to your project you can start using it.
  • Make sure you conform to both the iCarouselDelegate and iCarouselDataSource protocols.
  • 下载 iCarousel 并解压
  • 进入您解压的文件夹,打开其 iCarousel 子文件夹,然后选择 iCarousel.h 和 iCarousel.m 并将它们拖到您的项目导航中——这是 Xcode 的左窗格。就在 Info.plist 下面就可以了。
  • 选中“如果需要,请复制项目”,然后单击“完成”。
  • Xcode 会提示你“Would you like to configure an Objective-C bridging header?” 单击“Create Bridging Header” 您应该会在您的项目中看到一个名为 YourProjectName-Bridging-Header.h 的新文件。
  • 将此行添加到文件中:#import "iCarousel.h"
  • 将 iCarousel 添加到项目后,您就可以开始使用它了。
  • 确保您符合 iCarouselDelegate 和 iCarouselDataSource 协议。

Swift 3 Sample Code:

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
    }