2012-03-11 66 views
8

這個問題之前已經提出過,但方式稍有不同,我無法得到任何答案以我想要的方式工作,所以我很希望有很棒的核心動畫技能的人可以幫助我。如何在同時切換子視圖的同時圍繞x軸翻轉UIView

我在桌子上有一套卡。隨着用戶向上或向下滑動,一組卡片在桌子上上下移動。屏幕上可以看到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. 一旦我翻動了卡片,我無法讓動畫再次運行。換句話說,我可以根據需要多次運行動畫塊,但只有第一次會動畫。隨後我嘗試製作動畫會導致子視圖之間淡入淡出。

另外,請記住,我需要能夠與卡的表面進行交互。即它上面有按鈕。

如果有人遇到這些問題,很高興看到您的解決方案。更好的做法是在動畫上添加一個透視變換,使其具有更多的真實感。

回答

11

事實證明,這比我想象的要簡單,我不必使用任何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選項。順便提一句,蘋果在他們的文檔中有這個確切的代碼位。您還可以將其他動畫添加到塊,如調整大小和移動。

2

好吧,這不是一個完整的解決方案,但我會指出一些可能有用的東西。我不是Core-Animation大師,但我在程序中做了幾次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視圖(視圖的消失,視圖的出現,背面的視圖消失,以及背面 - 的視點到顯示)。最後,在第二個動畫的完成塊中,您可以做一些清理(重置視圖,旋轉並使其0.0f等)。

我知道這很複雜,所以你可能想閱讀Core-Animation的一些教程。

+0

感謝阿龍。 transitionWithView方法給了我一個解決方案的線索。話雖如此,你的確讓我更好地瞭解3D動畫。我需要投資一部好的核心動畫書。 – 2012-03-12 09:50:59

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,有一個翻轉卡。

+0

雖然此方法可行。當用戶需要與卡面交互時,我需要在卡上有交互式元素的UIViews。使用CALayer的只允許我使用圖像等 – 2012-03-12 09:49:50

+0

將這個層次結構放在一個包含'UIView',將處理交互... – 2012-03-12 10:47:59

+0

啊哈。指出。看起來像應該工作。謝謝。 – 2012-03-12 10:53:41

0

@ Paul.s

我也跟着用紙牌收納你的方法,但是當我applt卡容器旋轉動畫只有自己周圍的第一卡旋轉的一半,最後整個視圖appears.Each時間一面在動畫

0

基於Paul.s這是缺少的是更新的斯威夫特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,但由於該層有不同的zPositions不同層的「邊」將顯示

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") 
    }