@@ -10,17 +10,24 @@ import UIKit
1010
1111/// A view controller that manages a bottom sheet.
1212public class BottomSheetController : UIViewController {
13- // Holds the sheet content until the view is loaded
14- private let content : Content
13+ internal let content : Content
1514 private var shadowSize : CGSize = . zero
16- private let minimumTopOffset : CGFloat = 44
17- private let minimumContentHeight : CGFloat = 88
15+ internal var minimumTopOffsetAnchor : NSLayoutConstraint ?
1816 private var topAnchor : NSLayoutConstraint ?
19- private var indicatorTopAnchor : NSLayoutConstraint ?
17+ internal var indicatorTopAnchor : NSLayoutConstraint ?
2018 private var childHeightAnchor : NSLayoutConstraint ?
2119 private var panGesture : UIPanGestureRecognizer ?
2220 internal lazy var lastYOffset : CGFloat = { sheetView. frame. origin. y } ( )
2321
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+
2431 /// Minimum downward velocity beyond which we interpret a pan gesture as a downward swipe.
2532 public var dismissThresholdVelocity : CGFloat = 1000
2633
@@ -42,11 +49,11 @@ public class BottomSheetController: UIViewController {
4249 return view
4350 } ( )
4451 /// Bottom sheet drag indicator view.
45- public private ( set) var indicatorView : DragIndicatorView !
52+ public internal ( set) var indicatorView : DragIndicatorView !
4653 /// Container view for the drag indicator.
4754 internal let indicatorContainer = UIView ( )
4855 /// Bottom sheet header view.
49- public private ( set) var headerView : SheetHeaderView !
56+ public internal ( set) var headerView : SheetHeaderView !
5057 /// Holds the sheet's child content (view or view controller).
5158 let contentView : UIView = {
5259 let view = UIView ( )
@@ -55,7 +62,7 @@ public class BottomSheetController: UIViewController {
5562 } ( )
5663
5764 /// Comprises the indicator view, the header view, and the content view.
58- private let stackView : UIStackView = {
65+ let stackView : UIStackView = {
5966 let stackView = UIStackView ( )
6067 stackView. axis = . vertical
6168 stackView. alignment = . center
@@ -119,8 +126,11 @@ public class BottomSheetController: UIViewController {
119126 }
120127
121128 /// :nodoc:
122- internal required init ? ( coder: NSCoder ) { nil }
123-
129+ @available ( * , unavailable)
130+ required public init ? ( coder: NSCoder ) {
131+ fatalError ( " init(coder:) is not available for BottomSheetController " )
132+ }
133+
124134 /// :nodoc:
125135 public override func viewDidLoad( ) {
126136 super. viewDidLoad ( )
@@ -159,105 +169,34 @@ public class BottomSheetController: UIViewController {
159169 }
160170}
161171
162- private extension BottomSheetController {
163- func commonInit( ) {
164- modalPresentationStyle = . custom
165- transitioningDelegate = self
166- }
167-
168- func build( ) {
169- switch content {
170- case . view( title: let title, view: let childView) :
171- build ( childView, title: title)
172- case . controller( let childController) :
173- build ( childController)
174- }
175- }
176-
177- func build( _ subview: UIView , title: String ) {
178- contentView. addSubview ( subview)
179- subview. constrainEdges ( )
180-
181- if let backgroundColor = subview. backgroundColor,
182- backgroundColor. rgbaComponents. alpha == 1 {
183- // use the subview's background color for the sheet
184- sheetView. backgroundColor = backgroundColor
185- // but we have to set the subview's background to nil or else
186- // it will overflow the sheet and not be cropped by the corner radius.
187- subview. backgroundColor = nil
188- }
189-
190- indicatorView = DragIndicatorView ( appearance: appearance. indicatorAppearance ?? . default)
191- indicatorContainer. addSubview ( indicatorView)
192-
193- headerView = SheetHeaderView ( title: title, appearance: appearance. headerAppearance ?? . default)
194- headerView. delegate = self
195- buildSheet ( )
196- }
197-
198- func build( _ childController: UIViewController ) {
199- addChild ( childController)
200- build ( childController. view, title: childController. title ?? " " )
201- childController. didMove ( toParent: self )
202- }
203-
204- func buildSheet( ) {
205- buildViews ( )
206- buildConstraints ( )
207- updateViewAppearance ( )
208- addGestures ( )
209- }
210-
211- func buildViews( ) {
212- view. addSubview ( dimmerView)
213- view. addSubview ( dimmerTapView)
214- view. addSubview ( sheetView)
215- sheetView. addSubview ( stackView)
216- stackView. addArrangedSubview ( indicatorContainer)
217- stackView. addArrangedSubview ( headerView)
218- stackView. addArrangedSubview ( contentView)
219- }
220-
221- func buildConstraints( ) {
222- dimmerView. constrainEdges ( )
223- dimmerTapView. constrainEdges ( . notBottom)
224- dimmerTapView. constrain ( . bottomAnchor, to: sheetView. topAnchor)
225-
226- sheetView. constrainEdges ( . notTop)
227- sheetView. constrain (
228- . topAnchor,
229- to: view. safeAreaLayoutGuide. topAnchor,
230- relatedBy: . greaterThanOrEqual,
231- constant: minimumTopOffset
232- )
233-
234- indicatorView. constrain ( . bottomAnchor, to: indicatorContainer. bottomAnchor)
235- indicatorTopAnchor = indicatorView. constrain (
236- . topAnchor,
237- to: indicatorContainer. topAnchor
238- )
239- indicatorView. constrainCenter ( . x)
240-
241- stackView. constrain ( . topAnchor, to: sheetView. topAnchor)
242- stackView. constrainEdges ( . horizontal, to: view. safeAreaLayoutGuide)
243- stackView. constrainEdges ( . bottom, to: view. safeAreaLayoutGuide, relatedBy: . greaterThanOrEqual)
244- stackView. constrainEdges ( . bottom, to: view. safeAreaLayoutGuide, priority: Priorities . sheetContentHugging)
245-
246- contentView. constrainEdges ( . horizontal)
247- headerView. constrainEdges ( . horizontal)
248- }
249-
172+ internal extension BottomSheetController {
250173 func updateViewAppearance( ) {
251174 dimmerTapView. isAccessibilityElement = appearance. isDismissAllowed
252175 sheetView. layer. cornerRadius = appearance. layout. cornerRadius
176+ minimumTopOffsetAnchor? . constant = appearance. minimumTopOffset
253177 updateShadow ( )
254178 dimmerView. backgroundColor = appearance. dimmerColor
255179 updateIndicatorView ( )
256180 updateHeaderView ( )
257181 updateChildView ( )
258182 view. layoutIfNeeded ( )
259183 }
260-
184+
185+ func addGestures( ) {
186+ let swipeGesture = UISwipeGestureRecognizer ( target: self , action: #selector( onSwipeDown) )
187+ swipeGesture. direction = . down
188+ view. addGestureRecognizer ( swipeGesture)
189+ let tapGesture = UITapGestureRecognizer ( target: self , action: #selector( onDimmerTap) )
190+ dimmerTapView. addGestureRecognizer ( tapGesture)
191+ }
192+ }
193+
194+ private extension BottomSheetController {
195+ func commonInit( ) {
196+ modalPresentationStyle = . custom
197+ transitioningDelegate = self
198+ }
199+
261200 func updateIndicatorView( ) {
262201 indicatorContainer. isHidden = !isResizable
263202 if let indicatorAppearance = appearance. indicatorAppearance {
@@ -313,14 +252,6 @@ private extension BottomSheetController {
313252 func updateShadow( ) {
314253 appearance. elevation? . apply ( layer: sheetView. layer)
315254 }
316-
317- func addGestures( ) {
318- let swipeGesture = UISwipeGestureRecognizer ( target: self , action: #selector( onSwipeDown) )
319- swipeGesture. direction = . down
320- view. addGestureRecognizer ( swipeGesture)
321- let tapGesture = UITapGestureRecognizer ( target: self , action: #selector( onDimmerTap) )
322- dimmerTapView. addGestureRecognizer ( tapGesture)
323- }
324255
325256 func onDismiss( ) {
326257 dismiss ( animated: true )
0 commit comments