9

以前有人问过这个问题,但方式略有不同,我无法得到任何答案以按照我想要的方式工作,所以我希望有出色的 Core Animation 技能的人可以帮助我。

我的桌子上有一组卡片。当用户向上或向下滑动时,一组卡片会在桌子上上下移动。在任何给定时间,屏幕上都会显示 4 张卡片,但只有第二张卡片显示其正面。当用户刷卡时,第二张卡会翻转回其正面,而下一张卡(取决于刷卡方向)会落在显示其正面的位置。

我已经像这样设置了我的卡片视图类:

@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 轴上只有一半的卡片是动画的。
  2. 一旦翻转,卡片的正面就会倒置并镜像。
  3. 一旦我翻转了卡片,我就无法让动画再次运行。换句话说,我可以根据需要多次运行动画块,但只有第一次才会动画。随后我尝试制作动画只会导致子视图之间的淡入淡出。

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

如果有人遇到这些问题,很高兴看到您的解决方案。更好的做法是为动画添加透视变换,以赋予它额外的真实感。

4

5 回答 5

12

This turned out to be way simpler than I thought and I didn't have to use any CoreAnimation libraries to achieve the effect. Thanks to @Aaron Hayman for the clue. I used transitionWithView:duration:options:animations:completion

My implementation inside the container view:

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

The trick was the UIViewAnimationOptionTransitionFlipFromBottom option. Incidentally, Apple has this exact bit of code in their documentation. You can also add other animations to the block like resizing and moving.

于 2012-03-12T09:48:32.123 回答
3

好的,这不是一个完整的解决方案,但我会指出一些可能有用的东西。我不是核心动画大师,但我在我的程序中做了一些 3D 旋转。

首先,没有“返回”视图。因此,如果您将某物旋转 M_PI(180 度),您将会像从背面一样查看该视图(这就是它被倒置/镜像的原因)。

我不确定你的意思是:

x 轴上只有一半的卡片是动画的。

但是,考虑您的锚点(发生旋转的点)可能会有所帮助。它通常位于中心,但通常您需要它位于其他位置。请注意,锚点表示为比例(百分比/ 100)......所以值是 0 - 1.0f。您只需设置一次(除非您需要更改)。以下是访问锚点的方法:

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

动画只运行一次的原因是变换是绝对的,而不是累积的。考虑到您总是从身份转换开始,然后对其进行修改,这很有意义......但基本上,没有动画发生,因为第二次没有动画(视图已经处于您的状态)要求它在)。

如果您要从一个视图动画到另一个视图(并且不能使用[UIView transitionWithView:duration:options:animations:completion:];),则必须使用两阶段动画。在动画的第一阶段,对于被翻转到背面的“卡片”,您将“向上/向下/随便”的视图旋转到 M_PI_2(此时它将“消失”,或不可见,因为它是旋转的)。在第二阶段,您将视图的背面旋转到 0(这应该是身份转换......也就是视图的正常状态)。此外,您必须对出现的“卡片”(正面)执行完全相反的操作。您可以通过实施另一个[UIView animateWithDuration:...]在第一个的完成块中。不过我会警告你,这样做可能会有点复杂。特别是因为您希望视图具有“背面”,这基本上需要为 4 个视图设置动画(视图消失、视图显示、视图消失和背面)视图到出现)。最后,在第二个动画的完成块中,您可以进行一些清理(重置旋转的视图并使其 alpha 为 0.0f 等...)。

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

于 2012-03-11T15:39:34.040 回答
1

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

最简单的解决方案是使用CATransformLayer,它允许您将其他CALayer放置在内部并保持它们的 3D 层次结构。

例如,要创建具有正面和背面的“卡片”,您可以执行以下操作:

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并拥有一张翻转卡。

于 2012-03-11T20:18:35.470 回答
0

@Paul.s

我在卡片容器上遵循了您的方法,但是当我在卡片容器上应用旋转动画时,只有第一张卡片的一半围绕自身旋转,最后出现整个视图。每次动画中都缺少一侧

于 2012-05-23T20:04:07.023 回答
0

基于Paul.s此为 Swift 3 更新,并将对角翻转卡片:

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 度设置动画,但由于图层具有不同的 zPosition,因此图层的不同“侧面”将显示

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")
  }
于 2017-06-08T20:54:00.853 回答