我如何应用一个透视图转换到一个UIView?

我希望在一个UIView上执行一个视角转换(如在coverflow中所见)

有人知道这是可能的吗?

我已经调查使用CALayer,并运行了所有实用的程序员核心动画播客,但我仍然不清楚如何在iPhone上创建这种转换。

任何帮助,指针或示例代码片段将非常感激!

110104 次浏览

你只能使用核心图形(石英,仅2D)转换直接应用到一个UIView的转换属性。为了在覆盖流中获得效果,你必须使用CATransform3D,它应用于3-D空间,因此可以给你想要的透视视图。你只能将CATransform3Ds应用到图层,而不是视图,所以你必须切换到图层。

查看Xcode附带的“CovertFlow”示例。它只适用于mac(不适用于iPhone),但很多概念都很好地转换了。

正如Ben所说,你需要使用UIView's层,使用CATransform3D来执行layer's rotation。让透视图工作的技巧,如这里描述,是直接访问CATransform3D (m34)的一个矩阵cells。矩阵数学从来不是我的菜,所以我不能准确地解释为什么它能起作用,但它确实起作用了。你需要将这个值设置为初始变换的负分数,然后应用你的图层旋转变换。你还应该能够做到以下几点:

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;

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

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

一个完整的例子(带有代码)可以在在这里中找到,其中我基于Bill Dudney的一个例子,在一对CALayers上实现了基于触摸的旋转和缩放。程序的最新版本,在页面的最底部,实现了这种透视图操作。代码应该相当容易阅读。

你在响应中引用的sublayerTransform是应用于你的UIView's CALayer的子层的转换。如果你没有任何子层,也不用担心。我在我的例子中使用了subblayertransform,只是因为在我旋转的一个层中包含了两个CALayers

你可以使用iCarousel SDK获得精确的旋转木马效果。

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

如果你之前没有将Objective-C代码添加到Swift项目中,请遵循以下步骤:

  • 下载iCarousel并解压
  • 进入你解压的文件夹,打开它的iCarousel子文件夹,然后选择iCarousel.h和iCarousel。m并将它们拖到项目导航中,也就是Xcode的左侧窗格。就在信息下面。Plist很好。
  • 勾选“如有需要复制项目”,然后单击“完成”。
  • Xcode会提示你“你想配置一个Objective-C桥接头吗?”点击“创建桥接头” 您应该在项目中看到一个名为YourProjectName-Bridging-Header.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
}

斯威夫特5.0

func makeTransform(horizontalDegree: CGFloat, verticalDegree: CGFloat, maxVertical: CGFloat,rotateDegree: CGFloat, maxHorizontal: CGFloat) -> CATransform3D {
var transform = CATransform3DIdentity
           

transform.m34 = 1 / -500
    

let xAnchor = (horizontalDegree / (2 * maxHorizontal)) + 0.5
let yAnchor = (verticalDegree / (-2 * maxVertical)) + 0.5
let anchor = CGPoint(x: xAnchor, y: yAnchor)
    

setAnchorPoint(anchorPoint: anchor, forView: self.imgView)
let hDegree  = (CGFloat(horizontalDegree) * .pi)  / 180
let vDegree  = (CGFloat(verticalDegree) * .pi)  / 180
let rDegree  = (CGFloat(rotateDegree) * .pi)  / 180
transform = CATransform3DRotate(transform, vDegree , 1, 0, 0)
transform = CATransform3DRotate(transform, hDegree , 0, 1, 0)
transform = CATransform3DRotate(transform, rDegree , 0, 0, 1)
    

return transform
}


func setAnchorPoint(anchorPoint: CGPoint, forView view: UIView) {
var newPoint = CGPoint(x: view.bounds.size.width * anchorPoint.x, y: view.bounds.size.height * anchorPoint.y)
var oldPoint = CGPoint(x: view.bounds.size.width * view.layer.anchorPoint.x, y: view.bounds.size.height * view.layer.anchorPoint.y)
    

newPoint = newPoint.applying(view.transform)
oldPoint = oldPoint.applying(view.transform)
    

var position = view.layer.position
position.x -= oldPoint.x
position.x += newPoint.x
    

position.y -= oldPoint.y
position.y += newPoint.y
    

print("Anchor: \(anchorPoint)")
    

view.layer.position = position
view.layer.anchorPoint = anchorPoint
}

你只需要用你的学位来调用这个函数。例如:

var transform = makeTransform(horizontalDegree: 20.0 , verticalDegree: 25.0, maxVertical: 25, rotateDegree: 20, maxHorizontal: 25)
imgView.layer.transform = transform