@@ -12,22 +12,17 @@ import UIKit
1212public class BottomSheetController : UIViewController {
1313 internal let content : Content
1414 private var shadowSize : CGSize = . zero
15+
1516 internal var minimumTopOffsetAnchor : NSLayoutConstraint ?
1617 private var topAnchor : NSLayoutConstraint ?
1718 internal var indicatorTopAnchor : NSLayoutConstraint ?
18- private var childHeightAnchor : NSLayoutConstraint ?
19+ private var maximumContentHeightAnchor : NSLayoutConstraint ?
20+ internal var idealContentHeightAnchor : NSLayoutConstraint ?
21+ internal var minimumContentHeightAnchor : NSLayoutConstraint ?
22+
1923 private var panGesture : UIPanGestureRecognizer ?
2024 internal lazy var lastYOffset : CGFloat = { sheetView. frame. origin. y } ( )
2125
22- /// Absolute minimum height of sheet content
23- ///
24- /// Only used when `appearance.minimumContentHeight == nil`.
25- public var minimumContentHeight : CGFloat = 88 {
26- didSet {
27- updateChildView ( )
28- }
29- }
30-
3126 /// Minimum downward velocity beyond which we interpret a pan gesture as a downward swipe.
3227 public var dismissThresholdVelocity : CGFloat = 1000
3328
@@ -42,9 +37,12 @@ public class BottomSheetController: UIViewController {
4237 /// Dimmer view.
4338 let dimmerView = UIView ( )
4439 /// Bottom sheet view.
45- let sheetView : UIView = {
40+ let sheetView = UIView ( )
41+ /// Bottom sheet container view.
42+ let sheetContainerView : UIView = {
4643 let view = UIView ( )
4744 view. layer. maskedCorners = [ . layerMaxXMinYCorner, . layerMinXMinYCorner]
45+ view. clipsToBounds = true
4846 view. backgroundColor = . systemBackground
4947 return view
5048 } ( )
@@ -55,11 +53,7 @@ public class BottomSheetController: UIViewController {
5553 /// Bottom sheet header view.
5654 public internal( set) var headerView : SheetHeaderView !
5755 /// Holds the sheet's child content (view or view controller).
58- let contentView : UIView = {
59- let view = UIView ( )
60- view. clipsToBounds = true
61- return view
62- } ( )
56+ let contentView = UIView ( )
6357
6458 /// Comprises the indicator view, the header view, and the content view.
6559 let stackView : UIStackView = {
@@ -150,7 +144,7 @@ public class BottomSheetController: UIViewController {
150144
151145 guard shadowSize != sheetView. bounds. size else { return }
152146 updateShadow ( )
153- shadowSize = contentView . bounds. size
147+ shadowSize = sheetView . bounds. size
154148 }
155149
156150 /// Performing the accessibility escape gesture dismisses the bottom sheet.
@@ -172,14 +166,13 @@ public class BottomSheetController: UIViewController {
172166internal extension BottomSheetController {
173167 func updateViewAppearance( ) {
174168 dimmerTapView. isAccessibilityElement = appearance. isDismissAllowed
175- sheetView . layer. cornerRadius = appearance. layout. cornerRadius
176- minimumTopOffsetAnchor? . constant = appearance. minimumTopOffset
169+ sheetContainerView . layer. cornerRadius = appearance. layout. cornerRadius
170+ minimumTopOffsetAnchor? . constant = appearance. layout . minimumTopOffset
177171 updateShadow ( )
178172 dimmerView. backgroundColor = appearance. dimmerColor
179173 updateIndicatorView ( )
180174 updateHeaderView ( )
181175 updateChildView ( )
182- view. layoutIfNeeded ( )
183176 }
184177
185178 func addGestures( ) {
@@ -189,6 +182,19 @@ internal extension BottomSheetController {
189182 let tapGesture = UITapGestureRecognizer ( target: self , action: #selector( onDimmerTap) )
190183 dimmerTapView. addGestureRecognizer ( tapGesture)
191184 }
185+
186+ var childContentSize : CGSize {
187+ switch content {
188+ case . view( _, let view) :
189+ return view. layoutSize
190+ case . controller( let viewController) :
191+ return viewController. layoutSize
192+ }
193+ }
194+
195+ func updateShadow( ) {
196+ appearance. elevation? . apply ( layer: sheetView. layer, cornerRadius: appearance. layout. cornerRadius)
197+ }
192198}
193199
194200private extension BottomSheetController {
@@ -226,33 +232,44 @@ private extension BottomSheetController {
226232 func updateChildView( ) {
227233 guard let childView = contentView. subviews. first else { return }
228234
229- let height : CGFloat
230- let priority : UILayoutPriority
231-
232- if let minimum = appearance. minimumContentHeight {
233- // If a minimum is specified, we make the sheet relatively easy to compress
234- // and enforce that specified minimum.
235- height = minimum
236- priority = Priorities . sheetCompressionResistanceLow
235+ // Enforce maximum height (if any)
236+ if let maximum = appearance. layout. maximumContentHeight {
237+ if let maximumContentHeightAnchor = maximumContentHeightAnchor {
238+ maximumContentHeightAnchor. constant = maximum
239+ } else {
240+ maximumContentHeightAnchor = childView. constrain (
241+ . heightAnchor,
242+ relatedBy: . lessThanOrEqual,
243+ constant: maximum
244+ )
245+ }
237246 } else {
238- // If no minimumContentHeight is specified, we make the sheet difficult
239- // to compress beyond intrinsicContentSize.height and enforce an absolute minimum.
240- height = minimumContentHeight // absolute minimum
241- priority = Priorities . sheetCompressionResistanceHigh
247+ maximumContentHeightAnchor? . isActive = false
242248 }
243249
244- childView. setContentCompressionResistancePriority ( priority, for: . vertical)
245- if let anchor = childHeightAnchor {
246- anchor. constant = height
250+ // Enforce ideal height (if any)
251+ // (otherwise sheet height defaults to childView.instrinsicContentSize.height)
252+ let idealHeight = appearance. layout. idealContentHeight ?? childContentSize. height
253+ if idealHeight > 0.0 {
254+ if let idealContentHeightAnchor = idealContentHeightAnchor {
255+ idealContentHeightAnchor. constant = idealHeight
256+ } else {
257+ idealContentHeightAnchor = childView. constrain (
258+ . heightAnchor,
259+ constant: idealHeight,
260+ priority: Priorities . idealContentSize
261+ )
262+ }
247263 } else {
248- childHeightAnchor = childView . constrain ( . heightAnchor , relatedBy : . greaterThanOrEqual , constant : height )
264+ idealContentHeightAnchor ? . isActive = false
249265 }
266+
267+ // Enforce minimum height
268+ minimumContentHeightAnchor? . constant = appearance. layout. minimumContentHeight
269+
270+ childView. setContentCompressionResistancePriority ( Priorities . sheetCompressionResistance, for: . vertical)
250271 }
251272
252- func updateShadow( ) {
253- appearance. elevation? . apply ( layer: sheetView. layer)
254- }
255-
256273 func onDismiss( ) {
257274 dismiss ( animated: true )
258275 }
0 commit comments