From dfdf88b2a41fbaef492f1e1936611ad7ae35a77e Mon Sep 17 00:00:00 2001 From: Yuki Date: Tue, 22 Oct 2024 11:32:09 -0700 Subject: [PATCH] Don't fade in/out embedded if there was no height change --- .../Embedded/EmbeddedPaymentElement.swift | 2 +- .../EmbeddedPaymentElementContainerView.swift | 48 +++++++++++-------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement.swift index a1ba6715ed0..26c303f9dae 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement.swift @@ -220,7 +220,7 @@ public final class EmbeddedPaymentElement { self.analyticsHelper = analyticsHelper analyticsHelper.logInitialized() - self.containerView.updateSuperviewHeight = { [weak self] in + self.containerView.needsUpdateSuperviewHeight = { [weak self] in guard let self else { return } self.delegate?.embeddedPaymentElementDidUpdateHeight(embeddedPaymentElement: self) } diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementContainerView.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementContainerView.swift index 1e147da327f..c141a2fdf25 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementContainerView.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementContainerView.swift @@ -8,14 +8,14 @@ import UIKit /// The view that's vended to the merchant, containing the embedded view. We use this to be able to swap out the embedded view with an animation when `update` is called. class EmbeddedPaymentElementContainerView: UIView { - var updateSuperviewHeight: () -> Void = {} - private var view: EmbeddedPaymentMethodsView + var needsUpdateSuperviewHeight: () -> Void = {} + private var contentView: EmbeddedPaymentMethodsView private var bottomAnchorConstraint: NSLayoutConstraint! init(embeddedPaymentMethodsView: EmbeddedPaymentMethodsView) { - self.view = embeddedPaymentMethodsView + self.contentView = embeddedPaymentMethodsView super.init(frame: .zero) - addInitialView(view) + addInitialView(contentView) } required init?(coder: NSCoder) { @@ -37,42 +37,52 @@ class EmbeddedPaymentElementContainerView: UIView { func updateEmbeddedPaymentMethodsView(_ embeddedPaymentMethodsView: EmbeddedPaymentMethodsView) { guard frame.size != .zero else { // A zero frame means we haven't been laid out yet. Simply replace the old view to avoid laying out before the view is ready and breaking constraints. - self.view.removeFromSuperview() - self.view = embeddedPaymentMethodsView + contentView.removeFromSuperview() + contentView = embeddedPaymentMethodsView addInitialView(embeddedPaymentMethodsView) return } - let oldView = view - let oldViewHeight = frame.height - // Add the new view w/ 0 alpha + let oldContentView = contentView + + // Add the new view embeddedPaymentMethodsView.translatesAutoresizingMaskIntoConstraints = false addSubview(embeddedPaymentMethodsView) - view = embeddedPaymentMethodsView - embeddedPaymentMethodsView.alpha = 0 + contentView = embeddedPaymentMethodsView NSLayoutConstraint.activate([ embeddedPaymentMethodsView.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor), embeddedPaymentMethodsView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), embeddedPaymentMethodsView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor), // Omit the bottom anchor so that the height is still fixed to the old view height ]) - // important that the view is already laid out before the animation block so that it doesn't animate from zero size. + + // Lay the new view out before the animation block so that it doesn't animate from zero size. layoutIfNeeded() + // Calculate heights of old and new content views to determine if height will change + let oldContentViewHeight = oldContentView.frame.size.height + let newContentViewHeight = embeddedPaymentMethodsView.frame.size.height + let heightWillChange = oldContentViewHeight != newContentViewHeight + + // Fade the old view out and the new view in if the height will change + if heightWillChange { + embeddedPaymentMethodsView.alpha = 0 + } UIView.animate(withDuration: 0.2) { // Re-pin bottom anchor to the new view, thus updating our height self.bottomAnchorConstraint.isActive = false self.bottomAnchorConstraint = embeddedPaymentMethodsView.bottomAnchor.constraint(equalTo: self.layoutMarginsGuide.bottomAnchor) self.bottomAnchorConstraint.isActive = true self.layoutIfNeeded() - // Fade old view out and new view in - oldView.alpha = 0 - embeddedPaymentMethodsView.alpha = 1 - if oldViewHeight != self.systemLayoutSizeFitting(.zero).height { - // Invoke EmbeddedPaymentElement delegate method so that height does not jump - self.updateSuperviewHeight() + if heightWillChange { + oldContentView.alpha = 0 + embeddedPaymentMethodsView.alpha = 1 + } + if heightWillChange { + // Invoke EmbeddedPaymentElement delegate method so that height of our superview does not jump + self.needsUpdateSuperviewHeight() } } completion: { _ in - oldView.removeFromSuperview() + oldContentView.removeFromSuperview() } } }