How to round shadow corners from curl animation of UIView?

115 views Asked by At

I am trying to animate UIView using UIView.transition with [.transitionCurlUp] as argument option. However, the corners are still shown as invisible elements that the shadow falls on: enter image description here

enter image description here

enter image description here

 class ViewController: UIViewController {

 @IBOutlet weak var buttonToBeCurled: UIView! {
    didSet {
        let tap = UITapGestureRecognizer(target: self, action: #selector(curlTappedView))
        buttonToBeCurled.addGestureRecognizer(tap)
        buttonToBeCurled.layer.cornerRadius = 35
        buttonToBeCurled.backgroundColor = UIColor.purple
    }
 }
 @objc func curlTappedView(_ gesture: UITapGestureRecognizer) {
    
    let tappedView = gesture.view!
    
    UIView.transition(with: tappedView, duration: 3.0, options: [.transitionCurlUp], animations: {
    })
  } 
}

Is there something about the way animation works while curling the uiview?

1

There are 1 answers

0
DonMag On

The shadow and its animation is generated internally by the transition, based on the view frame.

We can confirm that by using a plain, clear UIView:

enter image description here

This might work for you...

We'll embed the buttonToBeCurled view in a "container" UIView, set .clipsToBounds = true on the container, and give the container the same rounded corners:

class CurlViewController: UIViewController {
    
    var buttonToBeCurled = UIView()
    var containerView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()

        buttonToBeCurled.translatesAutoresizingMaskIntoConstraints = false
        containerView.translatesAutoresizingMaskIntoConstraints = false
        
        // embed the buttonToBeCurled view in a container
        containerView.addSubview(buttonToBeCurled)
        view.addSubview(containerView)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            
            // all four sides of buttonToBeCurled to container
            buttonToBeCurled.topAnchor.constraint(equalTo: containerView.topAnchor),
            buttonToBeCurled.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
            buttonToBeCurled.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
            buttonToBeCurled.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),

            // let's make it 300 x 200, centered
            containerView.widthAnchor.constraint(equalToConstant: 300.0),
            containerView.heightAnchor.constraint(equalToConstant: 200.0),
            containerView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            containerView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            
        ])
        
        buttonToBeCurled.backgroundColor = UIColor.purple
        buttonToBeCurled.layer.cornerRadius = 35

        // give container view the same corners
        containerView.layer.cornerRadius = buttonToBeCurled.layer.cornerRadius
        
        // clip its subview
        containerView.clipsToBounds = true
        
        let tap = UITapGestureRecognizer(target: self, action: #selector(curlTappedView))
        buttonToBeCurled.addGestureRecognizer(tap)

    }
    
    @objc func curlTappedView(_ gesture: UITapGestureRecognizer) {
        
        let tappedView = gesture.view!
        
        UIView.transition(with: tappedView, duration: 2.0, options: [.transitionCurlUp], animations: {
        })
    }
    
}

Here's how that looks, midway through the animation:

enter image description here

The visual effect looks okay, but... because the shadow animation outside the view bounds (which we now don't see) takes up time, there is a delay before the rest of the animation begins.

Using a shorter duration, and using .curveLinear instead of the default curveEaseInOut produces a somewhat better result.

    UIView.transition(with: tappedView, duration: 1.0, options: [.transitionCurlUp, .curveLinear], animations: {
    })