Ios 如何将透视变换应用于UIView?
我希望在UIView上执行透视变换(如coverflow中所示) 有人知道这是否可能吗 我已经研究过如何使用Ios 如何将透视变换应用于UIView?,ios,cocoa-touch,uiview,core-animation,calayer,Ios,Cocoa Touch,Uiview,Core Animation,Calayer,我希望在UIView上执行透视变换(如coverflow中所示) 有人知道这是否可能吗 我已经研究过如何使用CALayer,并浏览了所有实用的程序员核心动画播客,但我仍然不清楚如何在iPhone上创建这种转换 任何帮助、指针或示例代码片段都将不胜感激 只能使用直接应用于UIView变换属性的核心图形(仅限于石英、2D)变换。要在coverflow中获得效果,您必须使用CATTransform3D,它应用于三维空间,因此可以为您提供所需的透视图。只能将CATTransferM3D应用于图层,而不能
CALayer
,并浏览了所有实用的程序员核心动画播客,但我仍然不清楚如何在iPhone上创建这种转换
任何帮助、指针或示例代码片段都将不胜感激 只能使用直接应用于UIView变换属性的核心图形(仅限于石英、2D)变换。要在coverflow中获得效果,您必须使用CATTransform3D,它应用于三维空间,因此可以为您提供所需的透视图。只能将CATTransferM3D应用于图层,而不能应用于视图,因此必须切换到图层
查看Xcode附带的“CovertFlow”示例。它仅适用于mac(即不适用于iPhone),但很多概念都能很好地转换。正如Ben所说,您需要使用
UIView的
层,使用CATTransferorM3D
执行层的
旋转。让透视图正常工作的诀窍是直接访问CATTransformM3D
(m34)的矩阵单元之一。矩阵数学从来都不是我喜欢的东西,所以我不能确切地解释为什么它会起作用,但它确实起作用。对于初始变换,需要将该值设置为负分数,然后将层旋转变换应用于该值。您还应该能够执行以下操作:
目标-C
UIView*myView=[[self-subviews]objectAtIndex:0];
CALayer*layer=myView.layer;
CATTransferM3D旋转和透视变换=CATTransferM3D实体;
旋转和透视变换.m34=1.0/-500;
旋转和透视变换=CATTransformorM3dRotate(旋转和透视变换,45.0f*M_PI/180.0f,0.0f,1.0f,0.0f);
layer.transform=旋转和透视变换;
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
}
如果让myView=self.subviews.first{
let layer=myView.layer
var rotationAndPerspectiveTransform=CATTransferorM3DidEntity
旋转和透视变换.m34=1.0/-500
rotationAndPerspectiveTransform=CATTransformerM3Drotate(rotationAndPerspectiveTransform,45.0*.pi/180.0,0.0,1.0,0.0)
layer.transform=旋转和透视变换
}
这将为每次旋转从头开始重建层变换
可以找到一个完整的例子(带有代码),我在几个Calayer
上实现了基于触摸的旋转和缩放,基于Bill Dudney的例子。最新版本的程序在页面的最底部实现了这种透视操作。代码应该相当简单易读
您在响应中提到的子层转换
是应用于UIView的CALayer
子层的转换。如果没有任何子层,请不要担心。我在示例中使用sublayerTransform只是因为在我旋转的一个层中包含两个Calayer
。使用iCarousel SDK可以获得精确的旋转木马效果
通过使用神奇的免费iCarousel库,您可以在iOS上获得即时封面效果。通过添加桥接头(它是用Objective-C编写的),您可以很容易地从Xcode项目下载它并将其放到Xcode项目中
如果您以前没有将Objective-C代码添加到Swift项目中,请执行以下步骤:
- 下载iCarousel并解压缩它
- 进入您解压缩的文件夹,打开其iCarousel子文件夹,然后选择iCarousel.h和iCarousel.m并将它们拖到项目导航中–这是Xcode中的左窗格。就在Info.plist下面就可以了
- 选中“复制项目(如果需要)”,然后单击“完成”
- Xcode将提示您“是否要配置Objective-C桥接头?”单击“创建桥接头”
您应该在项目中看到一个新文件,名为YourProjectName bridgeing Header.h
- 将此行添加到文件:#导入“iCarousel.h”
- 一旦你将iCarousel添加到你的项目中,你就可以开始使用它了
- 确保您同时遵守ICARouseldLegate和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
}
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
我正在/Developer/Examples中寻找这个coverflow示例,但没有成功,你在哪里能找到它?它实际上是“CovertFlow”,它在/Developer/Examples/Quartz/Core Animation/中。谢谢Brad-你是一个明星。PS:很抱歉你的回答太晚了!Nick。这对我来说很好,只是我好像失去了一半的图像(沿垂直分割线)--有时是LHS,有时是RHS。@iPadDeveloper2011-很有可能,当同一平面上有另一个不透明视图或图层时,您正试图旋转视图或图层。从屏幕上投影出去的视图或图层的一半将位于该另一视图的下方,因此被隐藏。您可以重新排序视图层次结构,以防止出现这种情况r使用zPosition属性将前景视图移动到足够高的位置,使其高于将其切断的位置。仅供参考,m34单元格影响透视变换的原因是矩阵中的单元格影响世界空间Z值映射到剪辑空间W值(用于透视投影)的方式。请阅读同质变换矩阵以了解更多信息。@uerceg-您将想作为一个单独的问题来问这个问题,最好是用图像来说明正在发生的事情和您想要发生的事情。我不确定这是否适合u,但当我制作动画时,我发现m14更适合我,仅供参考:)谢谢!-你给出了哪些值?通过设置m14,你实际上是在倾斜t