When flipping (e.g. pi rotation) views at the same time on the same axis, the view hierarchy (which one is in front and which one is behind) seems to be disturbed.
In the GIF below, the grey view with the swift icon is in front and the blue view is behind.
You can notice that when the first rotation of the grey view reaches pi / 2, its transparency seems to be altered. In addition, when the grey finishes its first rotation, instead of staying behind the blue view, it appears to be in front during all the next rotation.
Now repeating the exact same animation, the blue view has now no colours applied but it is still in the view hierarchy behind the grey view, and still animated.
I am trying to achieved the same animation keeping the blue view on top of the grey view, without having any apparent transparency change on the grey view. I use UIViewPropertyAnimator
to be able to scrub the animation later on.
The following code describes a simplified flip method (as an UIView extension) the animation is based on.
extension UIView{
func flipping(_ times: Int = 1, to direction: FoldingDirection, within duration: Double = 0.01, startAfter delay: Double = 0) {
guard times > 0 else { return }
// resets the layer anchor point depending on the current transform states of the view (calling a specific method)
self.setAnchorPoint(at: direction.anchor())
// adding perspective effect
self.layer.transform.m34 = 1 / 250
// setting rotation axis
let axis: CGPoint = {
switch direction {
case .right, .left:
return CGPoint(x: 1, y: 0)
default:
return CGPoint(x: 0, y: 1)
}
}()
let flipDuration = duration > 0 ? duration / Double(times) : 0.01
// creating animator
let animator = UIViewPropertyAnimator(duration: flipDuration, curve: .linear) {
self.layer.transform = CATransform3DRotate(self.layer.transform, .pi, axis.y, axis.x, 0)
}
animator.startAnimation(afterDelay: delay)
animator.addCompletion { (position) in
if position == .end {
self.flipping(times - 1, to: direction, within: duration * ( 1 - 1 / Double(times)), startAfter: 0)
}
}
}
}
Calling the animation:
greyView.flipping(3, to: .right, within: 9, startAfter: 0)
blueView.flipping(2, to: .right, within: 6, startAfter: 3)
Thanks for your help!
EDIT After running multiple tests, it seems the view hierarchy is indeed changed during the animation: the rotation seems to be occurring behind the view plane.
In this kind of animations, their Zpostion is not assigned so that you cannot control which one is closer and the other one is farther.
Assign zPosition to layers at event time will fix your problems. You may compare
greyView.layer.zPosition = 20
blueView.layer.zPosition = -20
and
greyView.layer.zPosition = 200
blueView.layer.zPosition = -200
and you will know what I mean.