Before Everything
關注過 Kitten Yang 的同學可能知道,他寫過一篇博客也是講翻頁動畫
的。我現在讀大二,比 Kitten Yang 低一屆,學iOS有一年了,一直感覺沒進步。所以我就想找一些東西練練,看到 Kitten Yang 的博客后,頓時覺得激情澎湃。因為那炫酷的交互動畫,也因為牛逼的學長!
后續,我將不定期的重寫 Kitten Yang 的代碼,加入自己的理解和改動。也許沒有他的動畫炫酷,但是我想加入自己的思想,讓自己得意進步。所以,如果有錯誤的地方,還請大家幫我指出來,謝謝!總之, 學習感興趣的東西是一件愉快的事情!
效果圖
下面是效果圖,左邊是 Kitten Yang 的原作,右邊是我改動之后的效果,加入了左右滑動,但是由于 POP
的 kPopLayerRotationY
存在 Bug ,導致翻轉超過 M_PI_2
就會出錯!所以左右方向我設置的最大角度是 M_PI_2
。還有一點就是,由于我的代碼可能過于復雜,我就沒加入陰影效果。
源代碼:GitHub
實現思路
(1) 分離
根據 Kitten Yang 的分析,要將一張圖片從中間折疊并顯示不同的陰影是非常麻煩的,但是 他有特別的動畫技巧,他將一張圖片分為上下兩個 ImageView
這樣就可以分別操作,已達到折疊的效果。由于兩個 ImageView
在添加的時候連在一起,所以大家看上去是一個完整的圖片,看不出是兩個View。
那么,問題來了!如果要實現上下左右都可以折疊呢?
-
這還不簡單!分成 4 份不就可以了!
一開始,我也是這么想的,但是 Too Young, Too Simple!
如下圖所示:由于設置了
ImageView
的Transition3D
使得圖片在折疊的時候顯得更逼真,就像下面圖片的上部分。但是如果兩張連在一起的 View 同時折疊的話,就是下下部分這個吊樣子了! 中間紅色部分會重合!
-
于是我決定 動態裁剪 !一開始,設置圖片的時候不裁剪,使用一個和父視圖一樣大的
ImageView
用于占位,然后根據手指滑動的方向決定怎么裁剪,裁剪后,刪除占位視圖!- 如果是
左右
滑動,就豎直
的裁剪!形成左右兩個ImageView
- 如果是
上下
滑動,就水平
的裁剪!形成上下兩個ImageView
- 如果是
這么完美的解決問題了?我書讀的少,你不要騙我!
理想很豐滿,現實很骨感 ,我該怎么區分是左右滑動還是上下滑動呢? 請往下看!
(2) 手勢識別
-
眾所周知,iOS里的手勢識別可以區分方向的是:
UISwipeGestureRecognizer
,在將手勢添加到視圖時,可以指定手勢的方向UISwipeGestureRecognizerDirection
:UISwipeGestureRecognizerDirectionRight
UISwipeGestureRecognizerDirectionLeft
UISwipeGestureRecognizerDirectionUp
UISwipeGestureRecognizerDirectionDown
可是這個手勢,只會識別一次。就是說它的監聽方法只會執行一次。由于這里需要根據手指滑動的長度決定圖片折疊的角度,所以這個手勢并不適用!
-
于是只能使用
UIPanGestureRecognizer
,然后根據手指滑動的初始點和第二次得到的點,計算手勢的方向。如下圖:
綠色的點代表手勢開始時的點 (第一次進入監聽方法時獲得的位置點),紅色的點代表第二次得到的點 (第二次進入監聽方法時獲得的位置點),算法如下:
//判斷手勢方向
func getDirection(location: CGPoint) -> PanDirection {
let dx = location.x - self.initialLocation.x
let dy = location.y - self.initialLocation.y
if abs(dx) > abs(dy) { //1.水平方向
if dx < 0 { //向左
return .left
} else { //向右
return .right
}
} else { //2.豎直方向
if dy < 0 { //向上
return .up
} else { //向下
return .down
}
}
}
總結
到此為止,我改寫的主要內容就是這些。對了還有一些代碼上的重構,不過我覺得重構的挺丑的,代碼看著也不舒服。希望看了我的代碼的同學跟我說說你們覺得應該怎么重構才能看的清爽。
建議大家先看 Kitten Yang
的 【POP動畫引擎教程 01】實現圖片折疊效果, 然后再回來看我這篇。當然啦,我這里寫的只是我寫代碼的思路,具體的代碼請到 這里 自取。