@@ -68,6 +68,7 @@ public class AnimatedCardsView: UIView {
68
68
private var cardCount = PrivateConstants . cardCount
69
69
private var maxVisibleCardCount = PrivateConstants . maxVisibleCardCount
70
70
private var gestureDirection : panScrollDirection = . Up
71
+ private var gestureTempCard : BaseCardView ?
71
72
72
73
private var currentIndex = 0
73
74
@@ -159,7 +160,7 @@ public class AnimatedCardsView: UIView {
159
160
- returns: if the action was performed or not (out of bounds)
160
161
*/
161
162
public func flipDown( ) -> Bool {
162
- guard currentIndex < cardCount && cardArray . count > 0 else {
163
+ guard currentIndex < cardCount else {
163
164
return false
164
165
}
165
166
@@ -183,6 +184,140 @@ public class AnimatedCardsView: UIView {
183
184
}
184
185
}
185
186
187
+ // MARK: Pan gesture
188
+ extension AnimatedCardsView {
189
+ @objc private func scrollOnView( gesture: UIPanGestureRecognizer ) {
190
+ let velocity = gesture. velocityInView ( self )
191
+ let percent = gesture. translationInView ( self ) . y/ 150
192
+ var flipTransform3D = CATransform3DIdentity
193
+ flipTransform3D. m34 = - 1.0 / 1000.0
194
+
195
+ switch gesture. state{
196
+ case . Began:
197
+
198
+ gestureDirection = velocity. y > 0 ? . Down : . Up
199
+
200
+ case . Changed:
201
+ let frontView : BaseCardView ? = cardArray. count > 0 ? cardArray [ 0 ] : nil
202
+
203
+ if gestureDirection == . Down{ // Flip down
204
+ guard currentIndex < cardCount else {
205
+ gesture. enabled = false // Cancel gesture
206
+ return
207
+ }
208
+
209
+ switch percent{
210
+ case 0.0 ..< 1.0 :
211
+ flipTransform3D = CATransform3DRotate ( flipTransform3D, CGFloat ( - M_PI) * percent, 1 , 0 , 0 )
212
+ frontView? . layer. transform = flipTransform3D
213
+ if percent >= 0.5 {
214
+ frontView? . contentVisible ( false )
215
+ } else {
216
+ frontView? . contentVisible ( true )
217
+ }
218
+ case 1.0 ... CGFloat ( MAXFLOAT) :
219
+ flipTransform3D = CATransform3DRotate ( flipTransform3D, CGFloat ( - M_PI) , 1 , 0 , 0 )
220
+ frontView? . layer. transform = flipTransform3D
221
+ default :
222
+ print ( percent)
223
+ }
224
+
225
+ } else { // Flip up
226
+ guard currentIndex > 0 else {
227
+ gesture. enabled = false // Cancel gesture
228
+ return
229
+ }
230
+
231
+ if gestureTempCard == nil {
232
+ let newView = addNewCardViewWithIndex ( currentIndex- 1 )
233
+ newView. layer. transform = flipDownTransform3D
234
+ gestureTempCard = newView
235
+ }
236
+
237
+ switch percent{
238
+ case CGFloat ( - MAXFLOAT) ... ( - 1.0 ) :
239
+ gestureTempCard!. layer. transform = CATransform3DIdentity
240
+ case - 1.0 ... 0 :
241
+ if percent <= - 0.5 {
242
+ gestureTempCard!. contentVisible ( true )
243
+ gestureTempCard!. layer. borderWidth = gestureTempCard!. frame. width / 100
244
+ } else {
245
+ gestureTempCard!. contentVisible ( false )
246
+ gestureTempCard!. layer. borderWidth = 0
247
+ }
248
+ flipTransform3D = CATransform3DRotate ( flipTransform3D, CGFloat ( - M_PI) * ( percent+ 1.0 ) , 1 , 0 , 0 )
249
+ gestureTempCard!. layer. transform = flipTransform3D
250
+ default :
251
+ print ( percent)
252
+ }
253
+ }
254
+
255
+ case . Ended:
256
+
257
+ switch gestureDirection{
258
+ case . Down:
259
+ if percent >= 0.5 {
260
+ currentIndex++
261
+
262
+ let frontView = cardArray. removeFirst ( )
263
+ let lastIndex = currentIndex + cardArray. count
264
+ if lastIndex < cardCount {
265
+ addNewCardViewWithIndex ( lastIndex, insertOnRear: true )
266
+ }
267
+
268
+ flipTransform3D = CATransform3DRotate ( flipTransform3D, CGFloat ( M_PI) , 1 , 0 , 0 )
269
+ UIView . animateWithDuration ( 0.3 , animations: {
270
+ frontView. layer. transform = flipTransform3D
271
+ } , completion: {
272
+ _ in
273
+ self . poolCardArray. append ( frontView)
274
+ frontView. removeFromSuperview ( )
275
+ self . relayoutSubViewsAnimated ( true )
276
+
277
+ } )
278
+ } else {
279
+ let frontView : BaseCardView ? = cardArray. count > 0 ? cardArray [ 0 ] : nil
280
+ UIView . animateWithDuration ( 0.2 , animations: {
281
+ frontView? . layer. transform = CATransform3DIdentity
282
+ } )
283
+
284
+ }
285
+
286
+ case . Up:
287
+ guard currentIndex > 0 else {
288
+ return
289
+ }
290
+
291
+ if percent <= - 0.5 {
292
+ currentIndex--
293
+ let shouldRemoveLast = cardArray. count > maxVisibleCardCount
294
+ UIView . animateWithDuration ( 0.2 , animations: {
295
+ self . gestureTempCard!. layer. transform = CATransform3DIdentity
296
+ } , completion: {
297
+ _ in
298
+ self . relayoutSubViewsAnimated ( true , removeLast: shouldRemoveLast)
299
+ self . gestureTempCard = nil
300
+ } )
301
+ } else {
302
+ UIView . animateWithDuration ( 0.2 , animations: {
303
+ self . gestureTempCard!. layer. transform = CATransform3DRotate ( flipTransform3D, CGFloat ( - M_PI) , 1 , 0 , 0 )
304
+ } , completion: {
305
+ _ in
306
+ self . poolCardArray. append ( self . gestureTempCard!)
307
+ self . cardArray. removeFirst ( )
308
+ self . gestureTempCard!. removeFromSuperview ( )
309
+ self . gestureTempCard = nil
310
+ } )
311
+ }
312
+ }
313
+ case . Cancelled: // When cancel reenable gesture
314
+ gesture. enabled = true
315
+ default :
316
+ print ( " DEFAULT: DO NOTHING " )
317
+ }
318
+ }
319
+ }
320
+
186
321
// MARK: Card Generation
187
322
extension AnimatedCardsView {
188
323
private func generateCards( ) {
@@ -202,7 +337,7 @@ extension AnimatedCardsView {
202
337
poolCardArray = [ ]
203
338
}
204
339
205
- private func addNewCardViewWithIndex( index: Int , insertOnRear rear: Bool = false ) -> UIView {
340
+ private func addNewCardViewWithIndex( index: Int , insertOnRear rear: Bool = false ) -> BaseCardView {
206
341
let newIndex = rear ? subviews. count : 0
207
342
var newView : BaseCardView ?
208
343
// Reuse cards
@@ -225,6 +360,7 @@ extension AnimatedCardsView {
225
360
if cardView != nil {
226
361
cardView!. layer. transform = flipUpTransform3D
227
362
cardView!. removeConstraints ( cardView!. constraints)
363
+ cardView!. prepareForReuse ( )
228
364
}
229
365
let view = self . dataSourceDelegate!. cardNumber ( index, reusedView: cardView)
230
366
view. translatesAutoresizingMaskIntoConstraints = false
0 commit comments