Issue with UIViewPropertyAnimator transform on iOS 14

I have an interactive transition which is working fine on iOS 13, but is broken on iOS 14. It uses UIViewPropertyAnimator to scale a UITableView down to a certain point at which point it triggers dismissal. In iOS 14 the table view's origin is offset as soon as the property animator kicks in.

Code sample here: https://gist.github.com/simonmitchell/eaad5f3649e6841934d209a3055be091

Is this an issue with what I'm doing? Or a known UIKit issue? See here for images: https://stackoverflow.com/questions/65436775/interactive-uiviewcontroller-transition-broken-on-ios-14
Could you explain more the use case. I looked at code and could not fully understand.

How is the transition initiated ?

I read in doc about scrollViewDidScroll
Code Block
optional func scrollViewDidScroll(_ scrollView: UIScrollView)

The delegate typically implements this method to obtain the change in content offset from scrollView and draw the affected portion of the content view.

Don't tou need to get the offset and adjust ?


The UIPanGestureRecognizer is what drives the animation, via the UIViewProperty’s “fractionComplete” property.
Have tried to replicate this with a simple example using a UISlider and UIViewPropertyAnimator and can't replicate, so I think it might be something to do with custom transitions, here is the code for that:

Code Block swift
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        guard let purchaseDetailVC = transitionContext.viewController(forKey: .to) as? PurchaseDetailViewController,
              let purchaseDetailView = transitionContext.view(forKey: .to) else {
            return
        }
        let toFrame = transitionContext.finalFrame(for: purchaseDetailVC)
        let dismissButton = UIButton()
        dismissButton.setBackgroundImage( imageLiteral(resourceName: "icon-close"), for: .normal)
        dismissButton.translatesAutoresizingMaskIntoConstraints = false
        let cardView: PurchaseView = PurchaseView(frame: .zero)
        cardView.translatesAutoresizingMaskIntoConstraints = false
        cardView.purchasable = fromCell.purchaseView.purchasable
        cardView.buyButtonState = fromCell.purchaseView.buyButtonState
        cardView.buyButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .title3).withWeight(.medium)
        cardView.addSubview(dismissButton)
        let buttonConstraints = [
            dismissButton.topAnchor.constraint(equalTo: cardView.topAnchor, constant: 20),
            dismissButton.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -20)
        ]
        NSLayoutConstraint.activate(buttonConstraints)
        let detailBGView = UIView(frame: .zero)
        detailBGView.translatesAutoresizingMaskIntoConstraints = false
        detailBGView.backgroundColor = purchaseDetailVC.tableView.backgroundColor
        // Card view constraints
        containerView.addSubview(detailBGView)
        let bgVerticalConstraint = detailBGView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor, constant: (fromFrame.height/2 + fromFrame.minY) - containerView.bounds.height/2)
        let bgConstraints = [
            bgVerticalConstraint,
            detailBGView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor)
        ]
        NSLayoutConstraint.activate(bgConstraints)
        let bgWidthConstraint = detailBGView.widthAnchor.constraint(equalToConstant: fromFrame.width)
        let bgHeightConstraint = detailBGView.heightAnchor.constraint(equalToConstant: fromFrame.height)
        NSLayoutConstraint.activate([bgWidthConstraint, bgHeightConstraint])
        containerView.addSubview(cardView)
        let verticalConstraint = cardView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor, constant: (fromFrame.height/2 + fromFrame.minY) - containerView.bounds.height/2)
        let cardConstraints = [
            verticalConstraint,
            cardView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor)
        ]
        NSLayoutConstraint.activate(cardConstraints)
        let cardWidthConstraint = cardView.widthAnchor.constraint(equalToConstant: fromFrame.width)
        let cardHeightConstraint = cardView.heightAnchor.constraint(equalToConstant: fromFrame.height)
        NSLayoutConstraint.activate([cardWidthConstraint, cardHeightConstraint])
        cardView.cornerRadius = 12
        cardView.cornerCurve = .continuous
        detailBGView.cornerRadius = 12
        detailBGView.cornerCurve = .continuous
        fromCell.isHidden = true
        fromCell.transform = .identity
        containerView.layoutIfNeeded()
        springAnimator.addAnimations {
            bgVerticalConstraint.constant = toFrame.minY/2
            verticalConstraint.constant = (purchaseDetailVC.headerHeight/2 - toFrame.height/2 + toFrame.minY/2)
            cardView.topConstraint.constant = purchaseDetailVC.purchaseView.topConstraint.constant
            containerView.layoutIfNeeded()
        }
        springAnimator.startAnimation()
        let expandingAnimator = UIViewPropertyAnimator(duration: springAnimator.duration * 0.6, curve: .linear)
        expandingAnimator.addAnimations {
cardView.containerView.borderWidth = 0.0
            cardView.buyButton.style = .onDarkBackground
            cardView.headlineHidden = true
            cardWidthConstraint.constant = toFrame.width
            cardHeightConstraint.constant = purchaseDetailVC.headerHeight
            bgWidthConstraint.constant = toFrame.width
            bgHeightConstraint.constant = toFrame.height
            // Must use layer because using view var breaks this for some reason
            cardView.layer.cornerRadius = 0.0
            detailBGView.layer.cornerRadius = 0.0
            containerView.layoutIfNeeded()
        }
        expandingAnimator.startAnimation()
        springAnimator.addCompletion { (_) in
            detailBGView.removeFromSuperview()
            cardView.removeFromSuperview()
            containerView.addSubview(purchaseDetailView)
            let success = !transitionContext.transitionWasCancelled
            transitionContext.completeTransition(success)
        }
    }


Issue with UIViewPropertyAnimator transform on iOS 14
 
 
Q