@@ -44,6 +44,9 @@ struct InteractiveDismissContainer<T: View>: UIViewControllerRepresentable {
4444 var onPan : ( CGPoint ) -> Void
4545 var isEnabled : Bool
4646 var isDismissing : Bool
47+
48+ var swipeUpToDismiss : Bool
49+
4750 var onDismiss : ( ) -> Void
4851 var onEnded : ( Bool ) -> Void
4952
@@ -59,7 +62,7 @@ struct InteractiveDismissContainer<T: View>: UIViewControllerRepresentable {
5962 }
6063
6164 func makeCoordinator( ) -> InteractiveDismissCoordinator {
62- InteractiveDismissCoordinator ( threshold: threshold, onPan: onPan, isEnabled: isEnabled, isDismissing: isDismissing, onDismiss: onDismiss, onEnded: onEnded)
65+ InteractiveDismissCoordinator ( threshold: threshold, onPan: onPan, isEnabled: isEnabled, isDismissing: isDismissing, swipeUpToDismiss : swipeUpToDismiss , onDismiss: onDismiss, onEnded: onEnded)
6366 }
6467}
6568
@@ -136,6 +139,9 @@ class InteractiveDismissCoordinator: NSObject, ObservableObject, UIGestureRecogn
136139 handleDismiss ( )
137140 }
138141 }
142+
143+ var swipeUpToDismiss : Bool
144+
139145 var onDismiss : ( ) -> Void
140146 var onEnded : ( Bool ) -> Void
141147
@@ -171,12 +177,13 @@ class InteractiveDismissCoordinator: NSObject, ObservableObject, UIGestureRecogn
171177 }
172178 }
173179
174- init ( threshold: Double , onPan: @escaping ( CGPoint ) -> Void , isEnabled: Bool , isDismissing: Bool , onDismiss: @escaping ( ) -> Void , onEnded: @escaping ( Bool ) -> Void ) {
180+ init ( threshold: Double , onPan: @escaping ( CGPoint ) -> Void , isEnabled: Bool , isDismissing: Bool , swipeUpToDismiss : Bool , onDismiss: @escaping ( ) -> Void , onEnded: @escaping ( Bool ) -> Void ) {
175181 self . threshold = threshold
176182
177183 self . onPan = onPan
178184 self . isEnabled = isEnabled
179185 self . isDismissing = isDismissing
186+ self . swipeUpToDismiss = swipeUpToDismiss
180187 self . onDismiss = onDismiss
181188 self . onEnded = onEnded
182189
@@ -215,7 +222,7 @@ class InteractiveDismissCoordinator: NSObject, ObservableObject, UIGestureRecogn
215222 isUpdating = true
216223 onPan ( offset)
217224
218- let shouldDismiss = offset. y > threshold || ( offset. x > threshold && isEdge)
225+ let shouldDismiss = offset. y > threshold || ( offset. x > threshold && isEdge) || ( - offset . y > threshold * 2 && swipeUpToDismiss )
219226 if shouldDismiss != isPastThreshold && shouldDismiss {
220227 impactGenerator. impactOccurred ( )
221228 }
@@ -237,9 +244,13 @@ class InteractiveDismissCoordinator: NSObject, ObservableObject, UIGestureRecogn
237244 func gestureRecognizerShouldBegin( _ gestureRecognizer: UIGestureRecognizer ) -> Bool {
238245 guard gestureRecognizer == panGestureRecognizer, let scrollView = scrollView else { return true }
239246
240- guard panGestureRecognizer. translation ( in: scrollView) . y > 0 else { return false }
241-
242- return scrollView. contentOffset. y - 5 <= - scrollView. contentInset. top
247+ if panGestureRecognizer. translation ( in: scrollView) . y > 0 {
248+ return scrollView. contentOffset. y - 5 <= - scrollView. contentInset. top
249+ } else {
250+ let belowBounds = scrollView. contentOffset. y + UIScreen. main. bounds. height > scrollView. contentSize. height + 20 && swipeUpToDismiss
251+ scrollView. isScrollEnabled = !belowBounds
252+ return belowBounds
253+ }
243254 }
244255
245256 func gestureRecognizer( _ gestureRecognizer: UIGestureRecognizer , shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer ) -> Bool {
@@ -248,6 +259,8 @@ class InteractiveDismissCoordinator: NSObject, ObservableObject, UIGestureRecogn
248259 return true
249260 }
250261
262+ scrollView. isScrollEnabled = true
263+
251264 if gestureRecognizer == panGestureRecognizer && otherGestureRecognizer == edgeGestureRecognizer {
252265 return false
253266 }
@@ -263,7 +276,6 @@ class InteractiveDismissCoordinator: NSObject, ObservableObject, UIGestureRecogn
263276 otherGestureRecognizer. isEnabled = false
264277 otherGestureRecognizer. isEnabled = true
265278 }
266-
267279 return true
268280 }
269281
@@ -278,7 +290,7 @@ class InteractiveDismissCoordinator: NSObject, ObservableObject, UIGestureRecogn
278290}
279291
280292extension View {
281- func onInteractiveDismissGesture( threshold: Double = 50 , isEnabled: Bool = true , isDismissing: Bool = false , onDismiss: @escaping ( ) -> Void , onPan: @escaping ( CGPoint ) -> Void = { _ in } , onEnded: @escaping ( Bool ) -> Void = { _ in } ) -> some View {
282- InteractiveDismissContainer ( threshold: threshold, onPan: onPan, isEnabled: isEnabled, isDismissing: isDismissing, onDismiss: onDismiss, onEnded: onEnded, content: self )
293+ func onInteractiveDismissGesture( threshold: Double = 50 , isEnabled: Bool = true , isDismissing: Bool = false , swipeUpToDismiss : Bool , onDismiss: @escaping ( ) -> Void , onPan: @escaping ( CGPoint ) -> Void = { _ in } , onEnded: @escaping ( Bool ) -> Void = { _ in } ) -> some View {
294+ InteractiveDismissContainer ( threshold: threshold, onPan: onPan, isEnabled: isEnabled, isDismissing: isDismissing, swipeUpToDismiss : swipeUpToDismiss , onDismiss: onDismiss, onEnded: onEnded, content: self )
283295 }
284296}
0 commit comments