I am building a card view - the selected card is on the top, the rest are on the bottom, stacked on top of each other. They all have the same superview.
The selected card has zPosition = 0, cards in the stack have increasing zPositions: 1,2,3 etc. Pre-Swap CardStack
When I pick a card from the stack, I animate its swap with the selected one (along with their zPositions) - something like Apple Wallet. Post-Swap CardStack - correct zPositions
After an animation, zPositions are set to the correct values, but the view hierarchy is invalid. View Hierarchy - Xcode visual debugger
Is it possible to achieve such animation using zPosition?
Swap animation code:
func didSelect(cardToBeSelected: CardView) {
guard alreadySelectedCard !== cardToBeSelected else {
return
}
guard let alreadySelectedCard = alreadySelectedCard else { return }
let destinationOriginY = alreadySelectedCard.frame.origin.y
let destinationZPosition = alreadySelectedCard.layer.zPosition
alreadySelectedCard.layer.zPosition = cardToBeSelected.layer.zPosition
let animator = UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut) {
self.alreadySelectedCard.frame.origin.y = cardToBeSelected.frame.origin.y
cardToBeSelected.frame.origin.y = destinationOriginY
self.view.layoutSubviews()
}
animator.addCompletion { (position) in
switch position {
case .end:
cardToBeSelected.layer.zPosition = destinationZPosition
default:
break
}
}
animator.startAnimation()
self.alreadySelectedCard = cardToBeSelected
}
I think you're going to run into a couple problems...
you're setting constraints and explicitly setting frames -- pretty much always asking for trouble
changing
layer.zPosition
does not change the object's order in the collection of subviewsusing vertical constraints relative to the bottom of the "top card" can get complicated when trying to change position / order of the cards
What I think would be a better approach:
insertSubview(_ view: UIView, belowSubview siblingSubview: UIView)
I see you're using SnapKit (personally, I don't like it, but anyway...)
From my quick searching, it seems really difficult to get a reference to a SnapKit constraint "on-the-fly" to get its
.constant
value. To get around that, you can add a property to yourCardView
class to keep a reference to its "snap top constraint."Here's your code from your pastebin link, modified as I described above. Please consider it example code -- but it may get your on your way. Much of it is the same - I added comments that will hopefully clarify the code I added / changed: