天天看點

iOS 動畫Animation-4-5: CALayer子類:CATransformLayer

首先說明:這是一系列文章,參考本專題下其他的文章有助于你對本文的了解。

今天周六,希望大家都有一個愉快的周末。

今天來講解一下CATransformLayer:CATransformLayer是一個專門用來建立三維視圖的一個layer,也可以說是多個layer的集合。他沒有多餘的API,可以這麼說,他隻是承載了子layer。

下面就看一個例子,通過例子來講解。

國際慣例先上圖:

iOS 動畫Animation-4-5: CALayer子類:CATransformLayer

圖就是這樣的純手工打造。

先建立一個CATransformLayer對象:

var transformLayer = CATransformLayer()
transformLayer.frame = someView.bounds
someView.layer.addSublayer(transformLayer)
           

這個沒有任何技術含量。同樣someView為我用storyboard建立的一個view

然後建立他的子layer,将layer添加到transformLayer上

var layer = sideLayerWithColor(redColor)
transformLayer.addSublayer(layer)

layer = sideLayerWithColor(orangeColor)
var transform = CATransform3DMakeTranslation(sideLength / , , sideLength / -)
transform = CATransform3DRotate(transform, degreesToRadians(), , , )
layer.transform = transform
transformLayer.addSublayer(layer)

layer = sideLayerWithColor(yellowColor)
layer.transform = CATransform3DMakeTranslation(, , -sideLength)
transformLayer.addSublayer(layer)

layer  = sideLayerWithColor(greenColor)
transform = CATransform3DMakeTranslation(sideLength / -, , sideLength / -)
transform = CATransform3DRotate(transform, degreesToRadians(), , , )
layer.transform = transform
transformLayer.addSublayer(layer)

layer = sideLayerWithColor(blueColor)
transform = CATransform3DTranslate(transform, , sideLength / -, sideLength / )
transform = CATransform3DRotate(transform, degreesToRadians(), , , )
layer.transform = transform
transformLayer.addSublayer(layer)

layer = sideLayerWithColor(purpleColor)
transform = CATransform3DMakeTranslation(, sideLength / , sideLength / -)
transform = CATransform3DRotate(transform, degreesToRadians(), , , )
layer.transform = transform
transformLayer.addSublayer(layer)

transformLayer.anchorPointZ = sideLength / -
           
  • 解釋:

    可以看到代碼分為六塊,這分别是建立一個立方體的六個面。不外乎都是根據第一個做了下旋轉和平移(如果有對這個不太了解的請看:iOS 動畫Animation-3: CATransform3D 特效詳解)

    再說到:sideLayerWithColor(purpleColor)這是什麼鬼?

    不要急,這是為了友善寫的一個建立layer的方法,内容如下

func sideLayerWithColor(color: UIColor) -> CALayer {
    let layer = CALayer()
    layer.frame = CGRect(origin: CGPointZero, size:   CGSize(width: sideLength, height: sideLength))
    layer.backgroundColor = color.CGColor
    return layer
}
           

還有一個:degreesToRadians(),這個是轉換角度,看上去更友善也更順眼。

func degreesToRadians(degrees: Double) -> CGFloat {
    return CGFloat(degrees * M_PI / )
}
           

括号内的參數分别是我定義的顔色來區分每個面的顔色不同

var redColor = UIColor.redColor()
var orangeColor = UIColor.orangeColor()
var yellowColor = UIColor.yellowColor()
var greenColor = UIColor.grayColor()
var purpleColor = UIColor.purpleColor()
var blueColor = UIColor.blueColor()
           

最後一行設定錨點,将錨點設定為立方體的中心

現在一個立方體已經做好了,但是運作之後看到的仍然是平面,因為這個立方體是正對着螢幕,其他面都被遮擋了。

下面就寫個方法讓他旋轉角度

func applyRoationForXOffset(xOffset: Double, yOffset: Double){

    let totalOffset = sqrt(xOffset * xOffset + yOffset * yOffset)
    let totalRotation = CGFloat(totalOffset * M_PI / )

    let xRotationalFactor = CGFloat(xOffset) / totalRotation
    let yRotationalFactor = CGFloat(yOffset) / totalRotation
    let currentTransform = CATransform3DTranslate(transformLayer.sublayerTransform, , , )

    let rotationTransform = CATransform3DRotate(transformLayer.sublayerTransform, totalRotation, xRotationalFactor * currentTransform.m12 - yRotationalFactor * currentTransform.m11,  xRotationalFactor * currentTransform.m22 - yRotationalFactor * currentTransform.m21, xRotationalFactor * currentTransform.m32 - yRotationalFactor * currentTransform.m31)
    print(currentTransform.m12, currentTransform.m11)
    transformLayer.sublayerTransform = rotationTransform
    }
           
  • 解釋

    第一個函數是求平方和然後開根,算出直線距離,

    CGFloat(totalOffset * M_PI / 180.0)是将移動距離轉回為角度

    初始化Transform

    關于矩陣變換不懂得也請參考:iOS 動畫Animation-3: CATransform3D 特效詳解)

    然後在适當的地方調用這個方法,(就是在添加完所有的子layer後)

給參數設定值之後就可以看到一個有立體效果的立方體了,

下面就開始讓這個立方體動起來,

手勢的操作,當然少不了touchBegan和touchMoved了。

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch: UITouch = touches.first!
    startPoint = touch.locationInView(someView)
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let touch: UITouch = touches.first!
    let currentPoint = touch.locationInView(someView)
    let deltaX = currentPoint.x - startPoint.x
    let deltaY = currentPoint.y - startPoint.y
    applyRoationForXOffset(Double(deltaX), yOffset: Double(deltaY))
    startPoint = touch.locationInView(someView)

}
           
  • 解釋

    在touchBegan的時候記錄下手指開始位置(startPoint)

    在touchMoved的時候記錄下手指目前的位置(currentPoint)

    然後通過計算的到x軸和y軸移動的距離

    調用讓立方體旋轉的方法:applyRoationForXOffset(Double(deltaX), yOffset: Double(deltaY))

    并且要及時的更新(startPoint)。

    好了,相信如上圖的效果也出來了,在這裡放上自己做的Demo,以便還不是很懂的童鞋參考一下。

對CALayer子類的介紹也告一段落了,但是不代表動畫的介紹就結束了,還沒呢!繼續關注吧!