Rotational Transformation and Card Dismiss
Tinder Firestore Swipe and Match
In this lesson, we'll dive into how we can apply some rotational transformation as we're panning our cards left and right. This is not incredibly difficult if you're aware of how to construct a rotational CGAffineTransform object using the appropriate angles. We'll look at how we can combine rotations and also translations as we're changing our gesture movements. Finally, we'll discuss how to dismiss our cards using a few different techniques involving transforms and frames. Enjoy.

Comments (12)
Nikhil Nangia
4 years ago
We have enabled landscape mode but image seems to be glitched then used in landscape mode? Is it just to ensure the autolayout part and in partical scenarios we would disable the capability or is there any hack to this problem, Like adding some scroll element or some resizing of imageview ?
Brian Voong
4 years ago
ravikanth.marri@gmail.com
4 years ago
Great suff , Thanks Brian. I was wondering Do you have any course that covers real time app Unit Testing. I would love to purchase that course.
Cinquain
4 years ago
This episode was even better!
Brian Voong
4 years ago
Daniel Peach
4 years ago
Loved the challenge. Great idea to implement this
Hoàng Cửu Long
4 years ago
Hi Brian, Here is my idea for the challenge fileprivate func handleGestureEnded(_ gesture: UIPanGestureRecognizer) { var shouldDismissCard = false let velocity = gesture.velocity(in: self) var direction: SwipeDirection = .right if velocity.x > 0 { direction = .right shouldDismissCard = gesture.translation(in: nil).x > threshold }else if (velocity.x < 0){ direction = .left shouldDismissCard = gesture.translation(in: nil).x < threshold } UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.1, options: .curveEaseOut, animations: { if shouldDismissCard { self.frame = CGRect(x: CGFloat(direction.rawValue) * 1000, y: 0, width: self.frame.width, height: self.frame.height) }else { self.transform = .identity } }) { (_) in self.transform = .identity self.frame = CGRect(x: 0, y: 0, width: self.superview!.frame.width, height: self.superview!.frame.height) } } enum SwipeDirection: Int { case left = -1 case right = 1 case down = -2 case up = 2 }
Brian Voong
4 years ago
rforbes1004
4 years ago
This is the best $80 ive ever spent. Nice work ma dood!
KevinKuo
4 years ago
Hi Brian, i have a problem when i move the card and the card come back is not back to the center, always show half on the screen i don't know why my code is same as your or even use your project always have this problem can you help me to figure out thanks
KevinKuo
4 years ago
sorry , i think i find the problem i think is just my mac is to low to run it stronger project
yongzhan
4 years ago
为什么我的项目中并没出现 “拖拽时卡片会跳动的bug”
arturfil@hotmail.com
4 years ago
Hi Brian, I have a question, when I run the app on an emulator the bottom icons look good but when I run it on my phone, the big icons look a bit streched, is there a way to format the codes in order to make them render less "streched"? Thanks in advance
Malik Hassnain
4 years ago
let translation = gesture.translation(in: nil) let shouldDismissCard = translation.x > threshold || translation.x < -threshold UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.1, options: .curveEaseOut, animations: { if shouldDismissCard { // // if translation.x > self.threshold { self.frame = CGRect(x: 1000, y: 0, width: self.frame.width, height: self.frame.height) }else if translation.x < -self.threshold { self.frame = CGRect(x: -1000, y: 0, width: self.frame.width, height: self.frame.height) } // let offScreenTransform = self.transform.translatedBy(x: 1000, y: 0) // self.transform = offScreenTransform }else { self.transform = .identity } }) { (_) in self.transform = .identity self.frame = CGRect(x: 0, y: 0, width: self.superview!.frame.width, height: self.superview!.frame.height) }
Christopher J. Roura
3 years ago
Hi Brian, I have found a bug and am not sure why it is happening. The card when animated off the screen doesn't fully animate off of the screen with the newest version of Xcode 11 and iOS 13. Instead it of translating off of the screen it moves to the right half of the screen and stays there. I have also downloaded your project and without making any modifications to your project I still had the same issue. On a separate note, in my version, I wanted to add the feature that changes the rotation angle to be positive or negative based on where the touch began on the card. So if the card is translated when tapped and dragged from the top the rotation angle would be positive and if it was tapped and dragged from the bottom half of the card the rotation angle would be negative. I am curious to know if the code I added would do the job correctly and wanted to know if you knew a cleaner and better solution. And again, just for clarification my code below was not inserted when I encountered the off screen translation issue. Thanks in advance and love these tutorials. // Added this to the configurations at the top of the file var rotateUpDown = 0 // Added this override function just above the handleChanged function override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { let position = touch.location(in: imageView) if position.y > 374.5 { rotateUpDown = -1 } else { rotateUpDown = 1 } } } // Lastly, I modified the angle in handleChanged() to account for the rotate angle change let angle = (degrees * .pi / 180) * CGFloat(rotateUpDown)
Stephan Dowless
3 years ago
Getting this same bug
Brian Voong
3 years ago
Christopher J. Roura
3 years ago
Thank you, appreciate it.
Dino32
3 years ago
Looking forward to your view at the code:)
Dino32
3 years ago
This helps to save the animation if shouldDismissCard { self.frame = CGRect(x: 1000 * translationDirection, y: 0, width: self.frame.width, height: self.frame.height) self.superview?.subviews.last?.layer.removeAllAnimations() } else { // bringing back to starting point self.transform = .identity }
Mondeezy
3 years ago
Any update to the fix? Thank you!
Kacper Piątkowski
3 years ago
self.layer.frame = CGRect(...)
Dino32
3 years ago
Dear Kasper, Big up! How come you find and solve that issue? Also I've removed this line - self.superview?.subviews.last?.layer.removeAllAnimations()
alexb
3 years ago
Hi do you have a solution to this bug? Cards appear off screen and then on screen from the other side and into the middle, and then they disappear a little bit after.
alexb
3 years ago
Hi do you have a solution for this? I have the same issue, the cards go off screen from one side and then re appear on screen from the other side until they disappear after a while.
Brian Voong
3 years ago
Ali_Engineer
3 years ago
Hi Brian, I have downloaded the project in episode 10 and the animation bug is not resolved. Have you managed to solve the bug? I am still experiencing it. It would be great to fix it.
최민섭
3 years ago
I found a solution to the cardview animation error in ios 13 version. See the code below. :) fileprivate func handleEnded(_ gesture: UIPanGestureRecognizer) { // determine dismiss card or not let translationDirection: CGFloat = gesture.translation(in: nil).x > 0 ? 1 : -1 let shouldDismissCard = abs(gesture.translation(in: nil).x) > threshold UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.1, options: .curveEaseOut, animations: { if shouldDismissCard { // self.frame = CGRect(x: 0, // y: 0, // width: self.frame.width, // height: self.frame.height) self.center = CGPoint(x: 1000 * translationDirection, y: 0) } else { self.transform = .identity } }) { (_) in self.transform = .identity self.frame = CGRect(x: 0, y: 0, width: self.superview!.frame.width, height: self.superview!.frame.height) } }
schmidtfx
3 years ago
Wow simple bug fix with self.center, works great! Thank you 최민섭
antoinenei
3 years ago
Thank you!!!
onggiahuy97
3 years ago
Thank you! This is something good to keep in mind :))
mrmillmill
3 years ago
Hello Brian and 최민섭 I am using 10.15.3 Catalina and Xcode 11.5 and my card view would start to move off screen but then bounce back and never actually move off screen. The response from 최민섭 fixed my issue.
HELP & SUPPORT