Skip to content

Commit

Permalink
Don't fade in/out embedded if there was no height change
Browse files Browse the repository at this point in the history
  • Loading branch information
yuki-stripe committed Oct 23, 2024
1 parent 6d884c3 commit dfdf88b
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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()
}
}
}

0 comments on commit dfdf88b

Please sign in to comment.