iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 8
0
Software Development

iOS Swift x Layout x Animation x Transition系列 第 8

Flip Card - 翻轉圖片

https://ithelp.ithome.com.tw/upload/images/20171227/20107329oKWUMAcoJj.png
我們可以通過 Core Animation 來對圖片做各種翻轉的操作。

這次想要讓使用者可以通過手勢來翻轉卡片。

FlipCard

FlipCard
當使用者在畫面上滑動的時候,根據使用者手指所在的位置來180度翻轉卡片。

當翻轉超過 90度的時候,會看得見背面那張圖片。


CALayer

在 ViewController 中建立一個繼承於 CALayer 的 cardLayer 並放在 view.layer 上

在 cardLayer 上我們會先放上一張圖片 ( img-card )

後面會提到為什麼要改變 anchorPoint.

let screen                       = UIScreen.main.bounds
let cardImage                    = UIImage(named: "img-card")!
let cardWidth                    = screen.width * 0.5
let cardHeight                   = cardImage.size.height * (cardWidth / cardImage.size.width)
cardLayer                        = CALayer()
cardLayer.contents               = cardImage.cgImage
cardLayer.anchorPoint            = CGPoint(x: 1.0, y: 0.5)
cardLayer.frame                  = CGRect(x: 0, y: 0, width: cardWidth, height: cardHeight)
cardLayer.position               = CGPoint(x: view.frame.midX, y: view.frame.midY / 2)
view.layer.addSublayer(cardLayer)

UIPanGesture

通過 UIPanGesture 來獲取手勢在 view 上拖動的情況

let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panHandler))
view.addGestureRecognizer(panGesture)

翻卡片的實作

通過 panHandler 拿到 UIPanGestureRecognizer 事件以後,

我們就可以使用 sender.location(in:view) 方法知道使用者在 view 上當前的座標。

架設使用者滑動到(點到)畫面的最中央時,卡牌就要正好 90度垂直於畫面,也就是手指到最右邊的時候卡片 180度翻開。

而為了讓圖片有翻動的效果:

  • 通過 CATransform3DIdentity m34 來實現透視。
  • 通過 CATransation 來實現翻轉
@objc private func panHandler(_ sender: UIPanGestureRecognizer) {
    let screen = UIScreen.main.bounds
    let point  = sender.location(in: view)
    
    // init perspective transform
    var perspectiveTransform = CATransform3DIdentity
    perspectiveTransform.m34 = -1.0 / 2000.0
    
    // roate - 將平面滑動的距離轉換成弧度
    let rate:CGFloat     = 180 / screen.width
    let angle            = point.x * rate * CGFloat(Double.pi) / 180.0
    perspectiveTransform = CATransform3DRotate(perspectiveTransform, angle, 0, 1, 0)
    CATransaction.setDisableActions(true)
    cardLayer.transform = perspectiveTransform
    
    // change image when roate over half
    cardLayer.contents = UIImage(named: point.x >= screen.width / 2.0 ? "img-tree" : "img-card")?.cgImage
    
    // when pan ended
    if sender.state == .ended {
        // init perspectiveTransform
        perspectiveTransform = CATransform3DIdentity
        perspectiveTransform.m34 = -1.0 / 2000.0

        // rotate
        let x:CGFloat = point.x >= (screen.width / 2) ? 180 : 0
        let angle     = x * CGFloat(Double.pi) / 180.0
        perspectiveTransform = CATransform3DRotate(perspectiveTransform, angle , 0, 1, 0)

        CATransaction.setDisableActions(false)
        cardLayer.transform = perspectiveTransform
    }

}

CATransform3D & m34 透視

m34 默認值是 0, 我們可以通過設置 m34 為 1.0 / d 來實現透視效果,d 代表視角相機和屏幕之間的距離。

CATransform3D CATransform3D

  • 左圖:未使用透視
  • 右圖:使用透視

CATransform3DRotate

旋轉圖片的方法,通過參數就能夠同時對 x,y,z 軸旋轉指定的度數,還能做形狀變化(比如透視)

CATransform3DRotate(_ t: CATransform3D, _ angle: CGFloat, _ x: CGFloat, _ y: CGFloat, _ z: CGFloat) -> CATransform3D

錨點 (AnchorPoint)

AnchorPoint 用來描述圖層的相對座標,圖層左上角是 (0,0) 右下角是 (1,1)
默認狀態下 AnchorPoint 位於圖層的正中間 (0.5, 0.5)

通過圖片來解釋看看,

  • 有個 View 它的 frame 是 (50, 50, 100, 100)
  • 它的 AnchorPoint 默認是 (0.5, 0.5)
  • 我們把它的 AnchorPoint 移動到 (1.0, 1.0)

看到結果顯示,position 並沒有改變,但是 frame 卻移動了位置。

https://ithelp.ithome.com.tw/upload/images/20171231/20107329sPODgS5xwQ.png

改變 Anchor Point 前後的翻拍情況

CATransform3DCATransform3D
左圖:當我們尚未移動錨點的時候
右圖:將錨點移動到  CGPoint(x: 1.0, y: 0.5) 的位置後。
右圖中,由於圖像的 Anchor Point 移動到了原本圖片右邊的中間 (1.0,0.5),所以能看到完整的翻卡的效果了。

參考


上一篇
Scratch Card - 刮刮樂的做法
下一篇
Image Filter - 濾鏡
系列文
iOS Swift x Layout x Animation x Transition30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言