如何绕着X轴翻转UIView,同时切换子视图

这个问题之前已经被问过了,但是方式稍有不同,我无法得到任何答案,所以我希望拥有出色核心animation技能的人能够帮助我。

我有一张桌子上的一套卡。 随着用户向上或向下滑动,该组卡片在桌子上上下移动。 在任何时候屏幕上都可以看到4张牌,但是只有第二张牌正在显示其脸部。 当用户滑动第二张卡时,将其翻转回到其面部,并且下一张卡(取决于滑动方向)落在显示其面部的位置。

我已经build立了我的卡片视图类如下所示:

@interface WLCard : UIView { UIView *_frontView; UIView *_backView; BOOL flipped; } 

而且我试过用这段代码翻转卡片:

 - (void) flipCard { [self.flipTimer invalidate]; if (flipped){ return; } id animationsBlock = ^{ self.backView.alpha = 1.0f; self.frontView.alpha = 0.0f; [self bringSubviewToFront:self.frontView]; flipped = YES; CALayer *layer = self.layer; CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity; rotationAndPerspectiveTransform.m34 = 1.0 / 500; rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, M_PI, 1.0f, 0.0f, 0.0f); layer.transform = rotationAndPerspectiveTransform; }; [UIView animateWithDuration:0.25 delay:0.0 options: UIViewAnimationCurveEaseInOut animations:animationsBlock completion:nil]; } 

这个代码的工作原理,但它有以下问题,我似乎无法弄清楚:

  1. x轴上只有一半的卡是animation的。
  2. 一旦翻转,卡的面朝上,并镜像。
  3. 一旦我翻过卡,我无法让animation再次运行。 换句话说,我可以根据需要多次运行animation块,但只有第一次会animation。 随后的时间,我尝试animation导致只是淡入和淡出之间的子视图。

另外,请记住,我需要能够与卡的表面进行交互。 即它有button。

如果有人遇到这些问题,很高兴看到你的解决scheme。 更好的办法是给animation添加一个透视变换,以增加一点现实感。

事实certificate,这比我想象的要简单,我不必使用任何CoreAnimation库来达到这个效果。 感谢@Aaron Hayman提供的线索。 我用了transitionWithView:duration:options:animations:completion

我在容器视图中的实现:

  [UIView transitionWithView:self duration:0.2 options:UIViewAnimationOptionTransitionFlipFromBottom animations: ^{ [self.backView removeFromSuperview]; [self addSubview:self.frontView]; } completion:NULL]; 

技巧是UIViewAnimationOptionTransitionFlipFromBottom选项。 顺便说一句,苹果在他们的文档中有这个确切的代码位。 您也可以添加其他animation块像resize和移动。

好吧,这不是一个完整的解决scheme,但我会指出一些可能有用的东西。 我不是Core-Animation大师,但是我在程序中做了几次3D旋转。

首先,没有“回”的观点。 所以,如果你通过M_PI(180度)旋转某个东西,你将会从后面看这个视图(这就是为什么它是颠倒/镜像的原因)。

我不确定你的意思是:

x轴上只有一半的卡是animation的。

但是,这可能有助于考虑你的定位点(发生旋转的点)。 它通常在中心,但通常你需要它。 请注意,锚点表示为比例(百分比/ 100)…所以这些值是0 – 1.0f。 你只需要设置一次(除非你需要改变)。 以下是您如何访问定位点:

layer.anchorPoint = CGPointMake(0.5f, 0.5f) //This is center

animation只运行一次的原因是因为转换是绝对的,而不是累积的。 考虑到你总是从身份转换开始,然后修改它,这是有道理的…但基本上,没有animation发生,因为没有什么animation第二次(视图已经处于你的状态请求它在)。

如果你从一个视图animation到另一个视图(你不能使用[UIView transitionWithView:duration:options:animations:completion:]; ),你必须使用一个两阶段animation。 在animation的第一个阶段,对于被翻转到背面的“卡片”,您将旋转视图到消失“向上/向下/不pipe”到M_PI_2(在这一点上它将“消失”,或不可见,因为它是旋转的)。 而在第二阶段,你将背面的视angular消失为0(这应该是身份转换…也就是视图的正常状态)。 另外,你必须对出现的(正面)“卡”做相反的处理。 你可以通过在第一个完成块中实现另一个[UIView animateWithDuration:...]来完成这个工作。 不过,我会提醒你的,这样做可能会有点复杂。 特别是因为你想要视图有一个“背面”,这将基本上需要animation4视图(视图消失,视图到出现,背面视图消失,背面 – 的视点到显示)。 最后,在第二个animation的完成块,你可以做一些清理(重置视图,旋转,并使其0.0.0,等等…)。

我知道这很复杂,所以你可能想阅读Core-Animation的一些教程。

@Aaron有一些很好的信息,你应该阅读。

最简单的解决scheme是使用一个CATransformLayer ,它允许你放置其他的CALayer,并保持它们的三维层次结构。

例如,要创build一个正面和背面的“卡”,你可以做这样的事情:

 CATransformLayer *cardContainer = [CATransformLayer layer]; cardContainer.frame = // some frame; CALayer *cardFront = [CALayer layer]; cardFront.frame = cardContainer.bounds; cardFront.zPosition = 2; // Higher than the zPosition of the back of the card cardFront.contents = (id)[UIImage imageNamed:@"cardFront"].CGImage; [cardContainer addSublayer:cardFront]; CALayer *cardBack = [CALayer layer]; cardBack.frame = cardContainer.bounds; cardBack.zPosition = 1; cardBack.contents = (id)[UIImage imageNamed:@"cardBack"].CGImage; // You may need to mirror this image [cardContainer addSublayer:cardBack]; 

有了这个,你现在可以将你的转换应用到cardContainer并有一个翻转卡。

@ Paul.s

我跟着你的卡片容器的方法,但是当我在卡片容器上应用旋转animation时,只有第一张卡片的一半绕着它自身旋转,最后出现整个视图。每次在animation中缺less一面

Paul.s为基础,Swift 3更新了它,并且将对angular翻转一张牌:

 func createLayers(){ transformationLayer = CATransformLayer(layer: CALayer()) transformationLayer.frame = CGRect(x: 15, y: 100, width: view.frame.width - 30, height: view.frame.width - 30) let black = CALayer() black.zPosition = 2 black.frame = transformationLayer.bounds black.backgroundColor = UIColor.black.cgColor transformationLayer.addSublayer(black) let blue = CALayer() blue.frame = transformationLayer.bounds blue.zPosition = 1 blue.backgroundColor = UIColor.blue.cgColor transformationLayer.addSublayer(blue) let tgr = UITapGestureRecognizer(target: self, action: #selector(recTap)) view.addGestureRecognizer(tgr) view.layer.addSublayer(transformationLayer) } 

为360度animation,但由于图层有不同的z位置,图层的不同“边”将显示

 func recTap(){ let animation = CABasicAnimation(keyPath: "transform") animation.delegate = self animation.duration = 2.0 animation.fillMode = kCAFillModeForwards animation.isRemovedOnCompletion = false animation.toValue = NSValue(caTransform3D: CATransform3DMakeRotation(CGFloat(Float.pi), 1, -1, 0)) transformationLayer.add(animation, forKey: "arbitrarykey") }