Skip to content

Commit 11767c0

Browse files
committed
Support new iOS 26 contentSwipe UIScreenEdgePanGestureRecognizer
1 parent a045724 commit 11767c0

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

compose/ui/ui/src/iosMain/kotlin/androidx/compose/ui/window/InputViews.ios.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import platform.CoreGraphics.CGPoint
4646
import platform.CoreGraphics.CGRectIsEmpty
4747
import platform.CoreGraphics.CGRectZero
4848
import platform.Foundation.NSSelectorFromString
49+
import platform.Foundation.NSStringFromClass
4950
import platform.UIKit.UIEvent
5051
import platform.UIKit.UIEventTypeTouches
5152
import platform.UIKit.UIGestureRecognizer
@@ -66,6 +67,7 @@ import platform.UIKit.UIView
6667
import platform.UIKit.endEditing
6768
import platform.UIKit.setAccessibilityElements
6869
import platform.UIKit.setState
70+
import platform.darwin.NSObject
6971

7072
/**
7173
* A reason for why touches are sent to Compose
@@ -295,7 +297,7 @@ private class TouchesGestureRecognizer(
295297
return if (isInChildHierarchy(preventedGestureRecognizer.view)) {
296298
super.canPreventGestureRecognizer(preventedGestureRecognizer)
297299
} else if (preventedGestureRecognizer is UIScreenEdgePanGestureRecognizer) {
298-
false
300+
preventedGestureRecognizer.isUINavigationControllerContentSwipeGestureRecognizer()
299301
} else {
300302
state == UIGestureRecognizerStatePossible || state.isOngoing
301303
}
@@ -872,3 +874,21 @@ private fun UIView?.hasTrackingUIScrollView(): Boolean {
872874
}
873875
return false
874876
}
877+
878+
/**
879+
* Detects the private UIKit recognizer that drives iOS 26 full-width `UINavigationController`
880+
* swipe-back interaction. It is a subclass of `UIScreenEdgePanGestureRecognizer` which can start
881+
* anywhere across the horizontal axis of the screen.
882+
*
883+
* Compose needs to be able to prevent this recognizer after Compose content consumes horizontal
884+
* movement, for example when a `HorizontalPager` handles the drag. Without that, UIKit can start
885+
* the navigation pop transition first and cancel Compose's touch stream.
886+
*/
887+
private fun UIGestureRecognizer.isUINavigationControllerContentSwipeGestureRecognizer(): Boolean =
888+
available(OS.Ios to OSVersion(major = 26)) &&
889+
this is UIScreenEdgePanGestureRecognizer &&
890+
className() == "_UIParallaxTransitionPanGestureRecognizer" &&
891+
name == "UINavigationController.contentSwipe"
892+
893+
@OptIn(BetaInteropApi::class)
894+
private fun NSObject.className() = this.`class`()?.let { NSStringFromClass(it) }

0 commit comments

Comments
 (0)