Skip to content

Commit ba51165

Browse files
WallabyStuffinteractord
authored andcommitted
feat: Added detent sheet
1 parent bd427e9 commit ba51165

5 files changed

Lines changed: 136 additions & 2 deletions

File tree

Examples/SingleNavigator/01-SingleBasic/SingleBasic/Page/Home/HomeView.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ struct HomeView: View {
4242
Text("open Page 2 as Sheet")
4343
.foregroundColor(.purple)
4444
}
45+
46+
Button(action: {
47+
if #available(iOS 15.0, *) {
48+
navigator.detentSheet(linkItem: .init(pathList: ["page1", "page2"]), isAnimated: true, configuration: .default)
49+
} else {
50+
navigator.sheet(linkItem: .init(pathList: ["page1", "page2"]), isAnimated: true)
51+
}
52+
}) {
53+
Text("open Page 2 as Detent Sheet")
54+
.foregroundColor(.purple)
55+
}
4556

4657
Button(action: {
4758
navigator.fullSheet(linkItem: .init(pathList: ["page1", "page2"]), isAnimated: true, prefersLargeTitles: true)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import UIKit
2+
3+
@available(iOS 15.0, *)
4+
public struct DetentConfiguration {
5+
6+
public static let `default` = DetentConfiguration(detents: [.medium(), .large()])
7+
8+
public let detents: [UISheetPresentationController.Detent]
9+
public let cornerRadius: CGFloat?
10+
public let largestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier?
11+
public let prefersScrollingExpandsWhenScrolledToEdge: Bool
12+
public let prefersGrabberVisible: Bool
13+
public let prefersEdgeAttachedInCompactHeight: Bool
14+
public let widthFollowsPreferredContentSizeWhenEdgeAttached: Bool
15+
public let selectedDetentIdentifier: UISheetPresentationController.Detent.Identifier?
16+
17+
/// Initializes a new DetentConfiguration.
18+
///
19+
/// - Parameters:
20+
/// - detents: An array of `UISheetPresentationController.Detent` defining the sizes of the sheet.
21+
/// - cornerRadius: An optional `CGFloat` specifying the corner radius of the sheet.
22+
/// - largestUndimmedDetentIdentifier: An optional detent identifier specifying the largest undimmed size.
23+
/// - prefersScrollingExpandsWhenScrolledToEdge: A Boolean value indicating if scrolling should expand the sheet.
24+
/// - prefersGrabberVisible: A Boolean value indicating if the grabber should be visible.
25+
/// - prefersEdgeAttachedInCompactHeight: A Boolean value indicating if the sheet should be edge-attached in compact height.
26+
/// - widthFollowsPreferredContentSizeWhenEdgeAttached: A Boolean value indicating if the sheet's width should follow the preferred content size when edge-attached.
27+
/// - selectedDetentIdentifier: An optional detent identifier specifying the currently selected detent.
28+
public init(
29+
detents: [UISheetPresentationController.Detent],
30+
cornerRadius: CGFloat? = nil,
31+
largestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? = nil,
32+
prefersScrollingExpandsWhenScrolledToEdge: Bool = true,
33+
prefersGrabberVisible: Bool = false,
34+
prefersEdgeAttachedInCompactHeight: Bool = false,
35+
widthFollowsPreferredContentSizeWhenEdgeAttached: Bool = false,
36+
selectedDetentIdentifier: UISheetPresentationController.Detent.Identifier? = nil
37+
) {
38+
self.detents = detents
39+
self.cornerRadius = cornerRadius
40+
self.largestUndimmedDetentIdentifier = largestUndimmedDetentIdentifier
41+
self.prefersScrollingExpandsWhenScrolledToEdge = prefersScrollingExpandsWhenScrolledToEdge
42+
self.prefersGrabberVisible = prefersGrabberVisible
43+
self.prefersEdgeAttachedInCompactHeight = prefersEdgeAttachedInCompactHeight
44+
self.widthFollowsPreferredContentSizeWhenEdgeAttached = widthFollowsPreferredContentSizeWhenEdgeAttached
45+
self.selectedDetentIdentifier = selectedDetentIdentifier
46+
}
47+
}

Sources/LinkNavigator/Core/Core/SingleLinkNavigator.swift

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,20 @@ extension SingleLinkNavigator {
140140
private func _sheet(linkItem: LinkItem, isAnimated: Bool) {
141141
sheetOpen(item: linkItem, isAnimated: isAnimated)
142142
}
143-
143+
144+
/// Opens a sheet with the specified link item and an option to animate the presentation.
145+
///
146+
/// - Parameters:
147+
/// - linkItem: An object representing the item to be presented in the sheet, can be a `String` or a dictionary with `String` keys and values as `ItemValue`.
148+
/// - isAnimated: A boolean to indicate if the presentation should be animated.
149+
/// - configuration: A `DetentConfiguration` object that defines the appearance and behavior of the sheet.
150+
///
151+
/// - Available from iOS 15.0 and later.
152+
@available(iOS 15.0, *)
153+
private func _detentSheet(linkItem: LinkItem, isAnimated: Bool, configuration: DetentConfiguration) {
154+
detentSheetOpen(item: linkItem, isAnimated: isAnimated, configuration: configuration)
155+
}
156+
144157
/// Opens a full-screen sheet with options for animation and large titles.
145158
///
146159
/// - Parameters:
@@ -401,6 +414,40 @@ extension SingleLinkNavigator {
401414
subController = newController
402415
}
403416
}
417+
418+
@available(iOS 15.0, *)
419+
public func detentSheetOpen(
420+
item: LinkItem,
421+
isAnimated: Bool,
422+
configuration: DetentConfiguration)
423+
{
424+
DispatchQueue.main.async { [weak self] in
425+
guard let self else { return }
426+
guard let rootController else { return }
427+
428+
rootController.dismiss(animated: true)
429+
let newController = UINavigationController()
430+
431+
if let sheetPresentationController = newController.sheetPresentationController {
432+
sheetPresentationController.detents = configuration.detents
433+
sheetPresentationController.preferredCornerRadius = configuration.cornerRadius
434+
sheetPresentationController.largestUndimmedDetentIdentifier = configuration.largestUndimmedDetentIdentifier
435+
sheetPresentationController.prefersScrollingExpandsWhenScrolledToEdge = configuration.prefersScrollingExpandsWhenScrolledToEdge
436+
sheetPresentationController.prefersGrabberVisible = configuration.prefersGrabberVisible
437+
sheetPresentationController.prefersEdgeAttachedInCompactHeight = configuration.prefersEdgeAttachedInCompactHeight
438+
sheetPresentationController.widthFollowsPreferredContentSizeWhenEdgeAttached = configuration.widthFollowsPreferredContentSizeWhenEdgeAttached
439+
sheetPresentationController.selectedDetentIdentifier = configuration.selectedDetentIdentifier
440+
}
441+
442+
newController.setViewControllers(
443+
navigationBuilder.build(item: item),
444+
animated: false)
445+
446+
rootController.present(newController, animated: isAnimated)
447+
448+
subController = newController
449+
}
450+
}
404451

405452
// MARK: Private
406453

@@ -435,6 +482,15 @@ extension SingleLinkNavigator: LinkNavigatorProtocol {
435482
public func sheet(linkItem: LinkItem, isAnimated: Bool) {
436483
_sheet(linkItem: linkItem, isAnimated: isAnimated)
437484
}
485+
486+
@available(iOS 15.0, *)
487+
public func detentSheet(
488+
linkItem: LinkItem,
489+
isAnimated: Bool,
490+
configuration: DetentConfiguration
491+
) {
492+
_detentSheet(linkItem: linkItem, isAnimated: isAnimated, configuration: configuration)
493+
}
438494

439495
public func fullSheet(linkItem: LinkItem, isAnimated: Bool, prefersLargeTitles: Bool?) {
440496
_fullSheet(linkItem: linkItem, isAnimated: isAnimated, prefersLargeTitles: prefersLargeTitles)

Sources/LinkNavigator/Core/Protocol/LinkNavigatorProtocol.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,22 @@ public protocol LinkNavigatorProtocol {
2525
/// - linkItem: The link item to present.
2626
/// - isAnimated: A Boolean value that determines whether the presentation is animated.
2727
func sheet(linkItem: LinkItem, isAnimated: Bool)
28-
28+
29+
/// Presents a sheet with the given link item.
30+
///
31+
/// - Parameters:
32+
/// - linkItem: The link item to present.
33+
/// - isAnimated: A Boolean value that determines whether the presentation is animated.
34+
/// - configuration: A `DetentConfiguration` object that defines the appearance and behavior of the sheet.
35+
///
36+
/// - Available from iOS 15.0 and later.
37+
@available(iOS 15.0, *)
38+
func detentSheet(
39+
linkItem: LinkItem,
40+
isAnimated: Bool,
41+
configuration: DetentConfiguration
42+
)
43+
2944
/// Presents a full sheet with the given link item.
3045
///
3146
/// - Parameters:

Sources/LinkNavigator/Test/SingleLinkNavigatorMock.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ extension SingleLinkNavigatorMock: LinkNavigatorProtocol {
118118
public func sheet(linkItem _: LinkItem, isAnimated _: Bool) {
119119
event.sheet += 1
120120
}
121+
122+
@available(iOS 15.0, *)
123+
public func detentSheet(linkItem: LinkItem, isAnimated: Bool, configuration: DetentConfiguration) {
124+
event.sheet += 1
125+
}
121126

122127
public func fullSheet(linkItem _: LinkItem, isAnimated _: Bool, prefersLargeTitles _: Bool?) {
123128
event.fullSheet += 1

0 commit comments

Comments
 (0)