Multiple Cards and User Model
Tinder Firestore Swipe and Match
Our application in its current state only supports a single card in the deck. Why don't we expand the functionality a bit by adding in multiple cards? To do this cleanly, let's take a look at how we could define a model object to encapsulate all of the information for a card. The information we decide to include in our model should not contain more than what is necessary for now.

Comments (13)
Anas Belkhadir
4 years ago
Thanks for your tutorial . i was wondering why you didn't use UICollectionView and inheritance from UICollectionViewFlowLayout to make multiple card, i think the advantage of that is gaining the power of managing memory since we dequeue the cell and reuse it the.
Brian Voong
4 years ago
Tokyojogo
4 years ago
Hi Brian, amazing tutorial! As a follow-up to the UICollectioinView question, how will performance be when its like a tinder app where you have hundreds or thousands of cards to display? Will you be addressing this later on?
sraffe
4 years ago
Hi Tokyojogo, I don't imagine Brian will be addressing that later on, but I figured I could add my take on the question based on my experience. Usually if you have that many cards to display, you wouldn't load and place them all on screen at once. You would load a certain number of them (let's say 10), and as the user is swiping, once they cross a certain threshold of these cars (let's say 7 cards), you would then go and load the next 10 cards to display. Technically, you could also handle it in a way where you always only have 2 cards on display, one to swipe and one under it. Once you dismiss the top card you would just create the next card with the next User's data and place it under the new top card.
Tokyojogo
4 years ago
Thanks sraffe. I'm imagining that but I would like to see how it can be implemented. Do you know of any resource that does this when its not a tableview or uicollectionview?
sraffe
4 years ago
Not really, I mean there are other resources similar to the CardView that Brian made in this tutorial, but nothing that is designed as a pack to front User to CardView resource. Generally, the information in the CardView is specific to a particular app and how they want to use it, so i don't imagine something like that would be around, unless you can find code to a sample mock-tinder app that has a backend as well
Bashir SK
4 years ago
Wow, this is amazing Brian. I am learning a lot especially with programmatic views. Been used to storyboards since i started learning how to code. I'm glad i subscribed. Cheers Brian.
Cinquain
4 years ago
That tutorial was so good!
yuiso
4 years ago
Hi Brain I really hope that your courses' price can be more flexible. I mean like, presell price, standard price, onsale price. And some discount to your loyal fans (like me, I've bought 4 of your courses)
Brian Voong
4 years ago
rehannali
4 years ago
It would be great if you do it for your supporters.
shravpar98
4 years ago
Hey brian, instead of images, i would like the user to be able to swipe on videos instead. Is that possible? if so, would you be able to explain how? thank you
Brian Voong
4 years ago
Daniel Peach
4 years ago
Anyone know how to fix that bug where the image comes back into view? I've tried a few things, but it still happens
Honoluuluu
4 years ago
Hi Brian, i completed the previous challenge but in a much different way. I was wondering if you would be able to explain what the following code is saying: let translationDirection: CGFloat = gesture.translation(in: nil).x > 0 ? 1 : -1 let shouldDimissCard = abs(gesture.translation(in: nil).x) > threshold thanks
Humberto De La Cruz
4 years ago
I believe this part " gesture.translation(in: nil).x > 0 ? 1" is saying "if the translation in the x axis is greater than zero (moving the card to the right) give the variable (translationDirection) a value of 1 " and the next part ": -1" it is saying "if not, give it a value of -1 (moving to the left)". So that tells the system whether to dismiss the card 1000 to the left or 1000 to the right via 1000 * translationDirection = 1000, which would result in 1000 or -1000 depending if is translationDirection is 1 or -1. This part "abs(gesture.translation(in: nil).x) > threshold" is first calculating the absolute value of the translation, so even if the translation is in the negative direction or to the left, the value will be converted into a positive number so you can compare it to the threshold of 100. If it is greater than the threshold (abs(101)=101 or abs(-101)=101), this will make the boolean "ShouldDismissCard" a value of true, and if it is less than the threshold, (abs(99)=99 or abs(-99)=99) a value of false.
Yunio
4 years ago
hey Brian I purchased most of your courses I was wondering 2 things I can't find online how do I erase a a picture from firebase but not the entire node. and also how do I find a node with childbyauto id in firebasedatabse
Yunio
4 years ago
if anyone in here has an answer pleas help me out here or email yuniolbm@gmail.com
mashype
4 years ago
Mine was pretty simple. Just create two boolean checks to see if it is swiping left or right and then reset the frame based on which condition was triggered: fileprivate func handleEnded(_ gesture: UIPanGestureRecognizer) { let shouldDismissCardRight = gesture.translation(in: nil).x > threshold let shouldDismissCardLeft = gesture.translation(in: nil).x < threshold * -1 UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.1, options: .curveEaseOut, animations: { if shouldDismissCardRight { self.frame = CGRect(x: 1000, y: 0, width: self.frame.width, height: self.frame.height) } else if shouldDismissCardLeft { self.frame = CGRect(x: -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) } }
David Guarino
4 years ago
socrates
4 years ago
Hey Brian, Thanks for a really great course! I enjoy every minute of it!!! By the way wanted to share some info about the User "BUG" -- I think there is a similar class name in FIRUserInfo. Hope this helps, and don't judge too hard, I am new to programming Cheers
Brian Voong
4 years ago
mrmillmill
3 years ago
Hi Brian, My card bounces back onto the screen partially when I try to drag off screen to the right or to the left. It does reset afterwards but for some reason the card will not leave the screen completely. Any help on this? Here is my current code: import UIKit class CardView: UIView { fileprivate let imageView = UIImageView(image: #imageLiteral(resourceName: "lady5c")) // Configurations fileprivate let threshold: CGFloat = 100 override init(frame: CGRect) { super.init(frame: frame) // custom drawing code layer.cornerRadius = 10 clipsToBounds = true addSubview(imageView) imageView.fillSuperview() let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan)) addGestureRecognizer(panGesture) } @objc fileprivate func handlePan(gesture: UIPanGestureRecognizer) { switch gesture.state { case .changed: handleChanged(gesture) case .ended: handleEnded(gesture: gesture) default: () } } fileprivate func handleChanged(_ gesture: UIPanGestureRecognizer) { let translation = gesture.translation(in: nil) //rotation //convert radians to degrees let degrees: CGFloat = translation.x / 20 let angle = degrees * .pi / 180 let rotationalTransformation = CGAffineTransform(rotationAngle: angle) self.transform = rotationalTransformation.translatedBy(x: translation.x, y: translation.y) } fileprivate func handleEnded(gesture: UIPanGestureRecognizer) { 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: 1000 * translationDirection, 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) } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
Brian Voong
3 years ago
mrmillmill
3 years ago
Thank you for the quick response Brian. Ok great I will watch out for those fixes. I was going to edit my comment after realizing I pasted far too much code but did not notice and edit button. Sorry for taking up so much comment realestate. Thanks again for everything!
mrmillmill
3 years ago
I love that at around 14:20 the image is smashed and skinny and Brian says,"She is a little skinny...maybe that's what she wants" lol. Perfect!
Jack Mai
3 years ago
HI, i keep running to this problem here: Value of type '(CGRect) -> CGRect' has no member 'height' this is the code within the animationt self.frame = CGRect(x: movingDirection * 600, y: 0, width: self.frame.width, height: self.frame.height) what should i do? Should I use self.center = CGfloat instead?
HELP & SUPPORT