我想在UIView上执行透视变换(例如在coverflow中看到的那样)。
有人知道是否可能吗?
我已经研究过使用CALayer
,并且已经通过所有务实的程序员Core Animation播客,但是我仍然不清楚如何在iPhone上创建这种类型的变换。
任何帮助、指导或示例代码片段都将非常感谢!
我想在UIView上执行透视变换(例如在coverflow中看到的那样)。
有人知道是否可能吗?
我已经研究过使用CALayer
,并且已经通过所有务实的程序员Core Animation播客,但是我仍然不清楚如何在iPhone上创建这种类型的变换。
任何帮助、指导或示例代码片段都将非常感谢!
就像Ben所说的那样,您需要使用CATransform3D
与UIView
的层(layer)一起工作,来执行旋转操作(rotation)。要使透视(perspective)生效,就像这里描述的那样,需要直接访问CATransform3D
矩阵中的一个元素(m34)。我不是数学专家,无法解释为什么这样做有效,但确实如此。您需要将该值设置为负分数以进行初始变换(transform),然后将图层旋转(transforms)应用于其上。您还可以做以下操作:
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
}
这会为每次旋转重新构建图层变换。
您可以在此处找到完整的示例(包括代码),我已经基于Bill Dudney的示例在一些CALayers
上实现了基于触摸的旋转和缩放。该页面最底部提供了程序的最新版本,其中包含这种透视操作。代码应该相对容易阅读。
您在回答中提到的sublayerTransform
是应用于UIView
的CALayer
子层的变换。如果您没有任何子层,请不必担心。我在示例中使用sublayerTransform仅是因为一个图层中包含两个CALayers
。
Swift 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
使用iCarousel SDK可以获得准确的旋转木马效果。
通过使用神奇而免费的iCarousel库,您可以在iOS上立即获得Cover Flow效果。 您可以从https://github.com/nicklockwood/iCarousel下载它,并通过添加桥接头文件(它是用Objective-C编写的)相对容易地将其放入Xcode项目中。
如果您以前没有将Objective-C代码添加到Swift项目中,请按照以下步骤操作:
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
}