@swmansion/react-native-bottom-sheet 0.10.0-next.1 → 0.10.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -292,12 +292,15 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
292
292
|
return
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
+
val previousMaxHeight = detentSpecs.maxOfOrNull { it.height } ?: resolvedMaxDetentHeight()
|
|
295
296
|
detentSpecs = resolvedDetents
|
|
296
297
|
if (width > 0 && height > 0 && detentSpecs.isNotEmpty()) {
|
|
297
298
|
layoutSheetContainer(width, height)
|
|
298
299
|
|
|
299
300
|
if (hasLaidOut && !isPanning) {
|
|
300
301
|
targetIndex = targetIndex.coerceIn(0, detentSpecs.size - 1)
|
|
302
|
+
val newMaxHeight = detentSpecs.maxOfOrNull { it.height } ?: resolvedMaxDetentHeight()
|
|
303
|
+
val targetTy = translationY(targetIndex)
|
|
301
304
|
if (activeAnimation != null && isTargetingClosedDetent) {
|
|
302
305
|
suppressScrimForClosingTarget = true
|
|
303
306
|
hideScrim()
|
|
@@ -309,17 +312,26 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
|
|
|
309
312
|
activeAnimation = null
|
|
310
313
|
activeAnimationEmitsSettle = false
|
|
311
314
|
stopChoreographer()
|
|
312
|
-
|
|
313
|
-
|
|
315
|
+
// Re-anchor the in-flight position to the new container height so the
|
|
316
|
+
// sheet surface keeps the same on-screen height across the resize.
|
|
317
|
+
val visibleHeight = previousMaxHeight - currentTy
|
|
318
|
+
sheetContainer.translationY = (newMaxHeight - visibleHeight).coerceIn(0f, newMaxHeight)
|
|
314
319
|
emitPosition()
|
|
315
320
|
snapToIndex(targetIndex, 0f, emitIndexChange = false, emitSettle = shouldEmitSettle)
|
|
316
321
|
} else {
|
|
317
|
-
val
|
|
318
|
-
val
|
|
319
|
-
if (
|
|
322
|
+
val currentVisibleHeight = previousMaxHeight - sheetContainer.translationY
|
|
323
|
+
val targetHeight = detentSpecs.getOrNull(targetIndex)?.height ?: 0f
|
|
324
|
+
if (targetHeight <= currentVisibleHeight + 0.5f) {
|
|
325
|
+
// Content shrank (or is unchanged): snap immediately. Animating here
|
|
326
|
+
// would expose blank space below the shrunken content.
|
|
320
327
|
sheetContainer.translationY = targetTy
|
|
321
328
|
emitPosition()
|
|
322
329
|
} else {
|
|
330
|
+
// Content grew: re-anchor at the current visible height, then animate
|
|
331
|
+
// up to the taller detent.
|
|
332
|
+
sheetContainer.translationY =
|
|
333
|
+
(newMaxHeight - currentVisibleHeight).coerceIn(0f, newMaxHeight)
|
|
334
|
+
emitPosition()
|
|
323
335
|
snapToIndex(targetIndex, 0f, emitIndexChange = false, emitSettle = false)
|
|
324
336
|
}
|
|
325
337
|
}
|
|
@@ -60,7 +60,8 @@ public final class RNSBottomSheetHostingView: UIView {
|
|
|
60
60
|
private var hasLaidOut = false
|
|
61
61
|
private var isPanning = false
|
|
62
62
|
private var isContentInteractionDisabled = false
|
|
63
|
-
private
|
|
63
|
+
private var contentHeightMarker: UIView?
|
|
64
|
+
private static var markerObservationContext = 0
|
|
64
65
|
|
|
65
66
|
override public init(frame: CGRect) {
|
|
66
67
|
super.init(frame: frame)
|
|
@@ -237,7 +238,7 @@ public final class RNSBottomSheetHostingView: UIView {
|
|
|
237
238
|
hasLaidOut = false
|
|
238
239
|
isPanning = false
|
|
239
240
|
setContentInteractionEnabled(true)
|
|
240
|
-
|
|
241
|
+
stopObservingContentHeightMarker()
|
|
241
242
|
sheetContainer.transform = .identity
|
|
242
243
|
scrimView.alpha = 0
|
|
243
244
|
scrimView.isHidden = true
|
|
@@ -576,6 +577,7 @@ public final class RNSBottomSheetHostingView: UIView {
|
|
|
576
577
|
return
|
|
577
578
|
}
|
|
578
579
|
|
|
580
|
+
let previousMaxHeight = maximumResolvedDetentHeight ?? resolvedMaxDetentHeight
|
|
579
581
|
detentSpecs = resolvedDetents
|
|
580
582
|
|
|
581
583
|
guard bounds.width > 0, bounds.height > 0, !detentSpecs.isEmpty else {
|
|
@@ -584,6 +586,8 @@ public final class RNSBottomSheetHostingView: UIView {
|
|
|
584
586
|
|
|
585
587
|
if hasLaidOut, !isPanning {
|
|
586
588
|
targetIndex = max(0, min(detentSpecs.count - 1, targetIndex))
|
|
589
|
+
let newMaxHeight = maximumResolvedDetentHeight ?? resolvedMaxDetentHeight
|
|
590
|
+
let targetTy = translationY(for: targetIndex)
|
|
587
591
|
|
|
588
592
|
if let animator = activeAnimator {
|
|
589
593
|
stopDisplayLink()
|
|
@@ -592,19 +596,27 @@ public final class RNSBottomSheetHostingView: UIView {
|
|
|
592
596
|
animator.stopAnimation(true)
|
|
593
597
|
activeAnimator = nil
|
|
594
598
|
activeAnimatorEmitsSettle = false
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
)
|
|
599
|
+
// Re-anchor the in-flight position to the new container height so the
|
|
600
|
+
// sheet surface keeps the same on-screen height across the resize.
|
|
601
|
+
let visibleHeight = previousMaxHeight - visualTy
|
|
602
|
+
let reanchoredTy = min(max(newMaxHeight - visibleHeight, 0), newMaxHeight)
|
|
603
|
+
sheetContainer.transform = CGAffineTransform(translationX: 0, y: reanchoredTy)
|
|
599
604
|
emitPosition()
|
|
600
605
|
snapToIndex(targetIndex, velocity: 0, emitIndexChange: false, emitSettle: shouldEmitSettle)
|
|
601
606
|
} else {
|
|
602
|
-
let
|
|
603
|
-
let
|
|
604
|
-
if
|
|
607
|
+
let currentVisibleHeight = previousMaxHeight - currentTranslationY
|
|
608
|
+
let targetHeight = detent(at: targetIndex).height
|
|
609
|
+
if targetHeight <= currentVisibleHeight + 0.5 {
|
|
610
|
+
// Content shrank (or is unchanged): snap immediately. Animating here
|
|
611
|
+
// would expose blank space below the shrunken content.
|
|
605
612
|
sheetContainer.transform = CGAffineTransform(translationX: 0, y: targetTy)
|
|
606
613
|
emitPosition()
|
|
607
614
|
} else {
|
|
615
|
+
// Content grew: re-anchor at the current visible height, then animate
|
|
616
|
+
// up to the taller detent.
|
|
617
|
+
let startTy = min(max(newMaxHeight - currentVisibleHeight, 0), newMaxHeight)
|
|
618
|
+
sheetContainer.transform = CGAffineTransform(translationX: 0, y: startTy)
|
|
619
|
+
emitPosition()
|
|
608
620
|
snapToIndex(targetIndex, velocity: 0, emitIndexChange: false, emitSettle: false)
|
|
609
621
|
}
|
|
610
622
|
}
|
|
@@ -612,7 +624,50 @@ public final class RNSBottomSheetHostingView: UIView {
|
|
|
612
624
|
}
|
|
613
625
|
|
|
614
626
|
private func refreshContentHeightMarker() {
|
|
615
|
-
|
|
627
|
+
let marker = findContentHeightMarker()
|
|
628
|
+
guard marker !== contentHeightMarker else { return }
|
|
629
|
+
stopObservingContentHeightMarker()
|
|
630
|
+
contentHeightMarker = marker
|
|
631
|
+
if let marker {
|
|
632
|
+
// The marker's frame is updated by React Native when content above it
|
|
633
|
+
// resizes; observe its layer so we can re-resolve detents immediately
|
|
634
|
+
// instead of waiting for an unrelated layout pass. This is the iOS
|
|
635
|
+
// counterpart to Android's OnLayoutChangeListener on the marker.
|
|
636
|
+
marker.layer.addObserver(
|
|
637
|
+
self, forKeyPath: "position", options: [], context: &Self.markerObservationContext
|
|
638
|
+
)
|
|
639
|
+
marker.layer.addObserver(
|
|
640
|
+
self, forKeyPath: "bounds", options: [], context: &Self.markerObservationContext
|
|
641
|
+
)
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private func stopObservingContentHeightMarker() {
|
|
646
|
+
guard let marker = contentHeightMarker else { return }
|
|
647
|
+
marker.layer.removeObserver(
|
|
648
|
+
self, forKeyPath: "position", context: &Self.markerObservationContext
|
|
649
|
+
)
|
|
650
|
+
marker.layer.removeObserver(
|
|
651
|
+
self, forKeyPath: "bounds", context: &Self.markerObservationContext
|
|
652
|
+
)
|
|
653
|
+
contentHeightMarker = nil
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
override public func observeValue(
|
|
657
|
+
forKeyPath keyPath: String?,
|
|
658
|
+
of object: Any?,
|
|
659
|
+
change: [NSKeyValueChangeKey: Any]?,
|
|
660
|
+
context: UnsafeMutableRawPointer?
|
|
661
|
+
) {
|
|
662
|
+
if context == &Self.markerObservationContext {
|
|
663
|
+
refreshDetentsFromLayout()
|
|
664
|
+
} else {
|
|
665
|
+
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
deinit {
|
|
670
|
+
stopObservingContentHeightMarker()
|
|
616
671
|
}
|
|
617
672
|
|
|
618
673
|
private func findContentHeightMarker() -> UIView? {
|
package/package.json
CHANGED