我的问题与如何模仿这种Carousel视图Youtube video 有关,仅使用UIView而不是图层或CALayer ,这意味着实际上是在变换UIViews自身。
我发现了一个堆栈溢出问题,它实际上能够转换 将CATransform3D转换为CGAffineTransform 。那是由某个天才here所写的作为答案,但是我的问题有点独特。
您在下面看到的动画正在使用CALayer进行创建。我需要创建相同的动画,但是要转换UIView而不是其图层。
应该是什么样子
代码(使用“图层”创建动画): 这将获取一个图像卡,该图像卡是附加了图像的CALayer()并进行转换,然后将其放置在图像轮播中。
注意:当用户平移以移动/动画轮播时,也将调用turnCarousel()。
let transformLayer = CATransformLayer()
func turnCarousel() {
guard let transformSubLayers = transformLayer.sublayers else {return}
let segmentForImageCard = CGFloat(360 / transformSubLayers.count)
var angleOffset = currentAngle
for layer in transformSubLayers {
var transform = CATransform3DIdentity
transform.m34 = -1 / 500
transform = CATransform3DRotate(transform, degreeToRadians(deg: angleOffset), 0, 1, 0)
transform = CATransform3DTranslate(transform, 0, 0, 175)
CATransaction.setAnimationDuration(0)
layer.transform = transform
angleOffset += segmentForImageCard
}
}
所以基本上已经接近了,但是似乎在正面被认为是 的卡片和背面在中的卡片存在缩放问题。 / em>。
为此,我要做的是使用UIImageView作为轮播的基本视图,然后向其中添加更多UIImageViews作为卡片。所以现在我们正在尝试对UIImageView / UIView进行转换
代码:
var carouselTestView = UIImageView()
func turnCarouselTestCarousel() {
let segmentForImageCard = CGFloat(360 / carouselTestView.subviews.count)
var angleOffset = currentAngleTestView
for subview in carouselTestView.subviews {
var transform2 = CATransform3DIdentity
transform2.m34 = -1 / 500
transform2 = CATransform3DRotate(transform2, degreeToRadians(deg: angleOffset), 0, 1, 0)
transform2 = CATransform3DTranslate(transform2, 0, 0, 175)
CATransaction.setAnimationDuration(0)
// m13, m23, m33, m43 are not important since the destination is a flat XY plane.
// m31, m32 are not important since they would multiply with z = 0.
// m34 is zeroed here, so that neutralizes foreshortening. We can't avoid that.
// m44 is implicitly 1 as CGAffineTransform's m33.
let fullTransform: CATransform3D = transform2
let affine = CGAffineTransform(a: fullTransform.m11, b: fullTransform.m12, c: fullTransform.m21, d: fullTransform.m22, tx: fullTransform.m41, ty: fullTransform.m42)
subview.transform = affine
angleOffset += segmentForImageCard
}
}
使用此功能添加实际上组成轮播的子图像,该功能仅会在我的资源文件夹中经过名为1 ... 6的图像的for循环。
代码:
func CreateCarousel() {
carouselTestView.frame.size = CGSize(width: self.view.frame.width, height: self.view.frame.height / 2.9)
carouselTestView.center = CGPoint(self.view.frame.width * 0.5, self.view.frame.height * 0.5)
carouselTestView.alpha = 1.0
carouselTestView.backgroundColor = UIColor.clear
carouselTestView.isUserInteractionEnabled = true
self.view.insertSubview(carouselTestView, at: 0)
for i in 1 ... 6 {
addImageCardTestCarousel(name: "\(i)")
}
// Set the carousel for the first time. So that now we can see it like an actual carousel animation
turnCarouselTestCarousel()
let panGestureRecognizerTestCarousel = UIPanGestureRecognizer(target: self, action: #selector(self.performPanActionTestCarousel(recognizer:)))
panGestureRecognizerTestCarousel.delegate = self
carouselTestView.addGestureRecognizer(panGestureRecognizerTestCarousel)
}
addImageCardTestCarousous函数在这里:
代码:
func addImageCardTestCarousel(name: String) {
let imageCardSize = CGSize(width: carouselTestView.frame.width / 2, height: carouselTestView.frame.height)
let cardPanel = UIImageView()
cardPanel.frame.size = CGSize(width: imageCardSize.width, height: imageCardSize.height)
cardPanel.frame.origin = CGPoint(carouselTestView.frame.size.width / 2 - imageCardSize.width / 2 , carouselTestView.frame.size.height / 2 - imageCardSize.height / 2)
guard let imageCardImage = UIImage(named: name) else {return}
cardPanel.image = imageCardImage
cardPanel.contentMode = .scaleAspectFill
cardPanel.layer.masksToBounds = true
cardPanel.layer.borderColor = UIColor.white.cgColor
cardPanel.layer.borderWidth = 1
cardPanel.layer.cornerRadius = cardPanel.frame.height / 50
carouselTestView.addSubview(cardPanel)
}
目的:
这样做的目的是我想构建一个UI,该UI可以在您看到的旋转卡上使用UIViews,而CALayer无法将UIView添加为子视图。它只能将UIView的图层添加到其自己的图层中。因此,要解决此问题,我需要使用UIViews而非CALayers来实现该动画。
答案 0 :(得分:0)
我解决了一个问题,即使您正好在正面触摸了一张卡,似乎位于最前面的视图实际上仍在抓住所有触摸,而背面卡会阻止触摸正面卡。所以我做了一个可以计算的函数。哪些视图在最前面。比禁用和启用触摸。就像当两张纸牌堆叠在一起时,向后的纸牌会阻止从前部进行的纸牌/ userInteraction。
代码:
func DetermineFrontViews(view subview: UIView, angle angleOffset: CGFloat) {
let looped = Int(angleOffset / 360) // must round down to Int()
let loopSubtractingReset = CGFloat(360 * looped) // multiply 360 how ever many times we have looped
let finalangle = angleOffset - loopSubtractingReset
if (finalangle >= -70 && finalangle <= 70) || (finalangle >= 290) || (finalangle <= -260) {
print("In front of view")
if subview.isUserInteractionEnabled == false {
subview.isUserInteractionEnabled = true
}
} else {
print("Back of view")
if subview.isUserInteractionEnabled == true {
subview.isUserInteractionEnabled = false
}
}
}
我在转弯功能中添加了此功能,以查看它是否可以跟踪位于转盘背面或正面的第一张卡。
if subview.layer.name == "1" {
DetermineFrontViews(view: subview, angle: angleOffset)
}