diff --git a/Framework/Sources/FloatingPanelController.swift b/Framework/Sources/FloatingPanelController.swift index 59347c6b..b03a128d 100644 --- a/Framework/Sources/FloatingPanelController.swift +++ b/Framework/Sources/FloatingPanelController.swift @@ -572,6 +572,26 @@ open class FloatingPanelController: UIViewController { activateLayout() } + /// Prepares an update to the layout object from the delegate. + /// + /// This method must eventually be balanced with a call to endUpdateLayout(). + /// It can be called in an animation block. + public func beginUpdateLayout() { + floatingPanel.layoutAdapter.beginUpdateHeight() + } + + /// Balances a previous call to beginUpdateLayout(), and updates the layout + /// object from the delegate and lays out the views managed by the + /// controller immediately. + /// + /// This method updates the `FloatingPanelLayout` object from the delegate and + /// then it calls `layoutIfNeeded()` of the root view to force the view + /// to update the floating panel's layout immediately. It can be called in an + /// animation block. + public func endUpdateLayout() { + updateLayout() + } + /// Returns the y-coordinate of the point at the origin of the surface view. public func originYOfSurface(for pos: FloatingPanelPosition) -> CGFloat { return floatingPanel.layoutAdapter.positionY(for: pos) diff --git a/Framework/Sources/FloatingPanelLayout.swift b/Framework/Sources/FloatingPanelLayout.swift index a4ecc621..2502fced 100644 --- a/Framework/Sources/FloatingPanelLayout.swift +++ b/Framework/Sources/FloatingPanelLayout.swift @@ -440,6 +440,26 @@ class FloatingPanelLayoutAdapter { surfaceView.bottomOverflow = vc.view.bounds.height + layout.topInteractionBuffer } + // Support for FloatingPanelController.beginUpdateLayout/endUpdateLayout. + // + /// This method must eventually be balanced with a call to updateHeight(). + func beginUpdateHeight() { + guard vc != nil else { return } + + // Deactivate the hard height constraint until updateHeight() + if let const = self.heightConstraint { + NSLayoutConstraint.deactivate([const]) + } + + // Activate a very weak temporary height constraint which makes sure the + // surface view is not totally free-form. + let heightConstraint = surfaceView.heightAnchor.constraint(equalToConstant: 0) + heightConstraint.priority = UILayoutPriority(1) + + NSLayoutConstraint.activate([heightConstraint]) + self.heightConstraint = heightConstraint + } + func updateInteractiveTopConstraint(diff: CGFloat, allowsTopBuffer: Bool, with behavior: FloatingPanelBehavior) { defer { layoutSurfaceIfNeeded() // MUST be called to update `surfaceView.frame`