react-native-screens 4.7.0-beta.3 → 4.7.0-beta.4
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.
- package/android/src/main/java/com/swmansion/rnscreens/ScreenStackFragment.kt +10 -2
- package/android/src/main/java/com/swmansion/rnscreens/events/ScreenAnimationDelegate.kt +88 -0
- package/android/src/main/java/com/swmansion/rnscreens/events/ScreenEventEmitter.kt +36 -0
- package/ios/RNSScreenContentWrapper.mm +19 -4
- package/package.json +1 -1
- package/android/src/main/java/com/swmansion/rnscreens/events/ScreenEventDelegate.kt +0 -48
|
@@ -45,8 +45,9 @@ import com.swmansion.rnscreens.bottomsheet.useSingleDetent
|
|
|
45
45
|
import com.swmansion.rnscreens.bottomsheet.useThreeDetents
|
|
46
46
|
import com.swmansion.rnscreens.bottomsheet.useTwoDetents
|
|
47
47
|
import com.swmansion.rnscreens.bottomsheet.usesFormSheetPresentation
|
|
48
|
+
import com.swmansion.rnscreens.events.ScreenAnimationDelegate
|
|
48
49
|
import com.swmansion.rnscreens.events.ScreenDismissedEvent
|
|
49
|
-
import com.swmansion.rnscreens.events.
|
|
50
|
+
import com.swmansion.rnscreens.events.ScreenEventEmitter
|
|
50
51
|
import com.swmansion.rnscreens.ext.recycle
|
|
51
52
|
import com.swmansion.rnscreens.transition.ExternalBoundaryValuesEvaluator
|
|
52
53
|
import com.swmansion.rnscreens.utils.DeviceUtils
|
|
@@ -366,7 +367,14 @@ class ScreenStackFragment :
|
|
|
366
367
|
}
|
|
367
368
|
animatorSet.play(alphaAnimator).with(slideAnimator)
|
|
368
369
|
}
|
|
369
|
-
animatorSet.addListener(
|
|
370
|
+
animatorSet.addListener(
|
|
371
|
+
ScreenAnimationDelegate(
|
|
372
|
+
this,
|
|
373
|
+
ScreenEventEmitter(this.screen),
|
|
374
|
+
if (enter) ScreenAnimationDelegate.AnimationType.ENTER
|
|
375
|
+
else ScreenAnimationDelegate.AnimationType.EXIT
|
|
376
|
+
)
|
|
377
|
+
)
|
|
370
378
|
return animatorSet
|
|
371
379
|
}
|
|
372
380
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
package com.swmansion.rnscreens.events
|
|
2
|
+
|
|
3
|
+
import android.animation.Animator
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import com.swmansion.rnscreens.ScreenStackFragmentWrapper
|
|
6
|
+
|
|
7
|
+
// The goal is to make this universal delegate for handling animation progress related logic.
|
|
8
|
+
// At this moment this class works only with form sheet presentation.
|
|
9
|
+
class ScreenAnimationDelegate(
|
|
10
|
+
private val wrapper: ScreenStackFragmentWrapper,
|
|
11
|
+
private val eventEmitter: ScreenEventEmitter?,
|
|
12
|
+
private val animationType: AnimationType,
|
|
13
|
+
) : Animator.AnimatorListener {
|
|
14
|
+
enum class AnimationType {
|
|
15
|
+
ENTER,
|
|
16
|
+
EXIT
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private var currentState: LifecycleState = LifecycleState.INITIALIZED
|
|
20
|
+
|
|
21
|
+
private fun progressState() {
|
|
22
|
+
currentState =
|
|
23
|
+
when (currentState) {
|
|
24
|
+
LifecycleState.INITIALIZED -> LifecycleState.START_DISPATCHED
|
|
25
|
+
LifecycleState.START_DISPATCHED -> LifecycleState.END_DISPATCHED
|
|
26
|
+
LifecycleState.END_DISPATCHED -> LifecycleState.END_DISPATCHED
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override fun onAnimationStart(animation: Animator) {
|
|
31
|
+
if (currentState === LifecycleState.INITIALIZED) {
|
|
32
|
+
progressState()
|
|
33
|
+
|
|
34
|
+
// These callbacks do not work as expected from this call site, TODO: investigate it.
|
|
35
|
+
// To fix it quickly we emit required events manually
|
|
36
|
+
// wrapper.onViewAnimationStart()
|
|
37
|
+
|
|
38
|
+
when (animationType) {
|
|
39
|
+
AnimationType.ENTER -> eventEmitter?.dispatchOnWillAppear()
|
|
40
|
+
AnimationType.EXIT -> eventEmitter?.dispatchOnWillDisappear()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
val isExitAnimation = animationType === AnimationType.EXIT
|
|
44
|
+
eventEmitter?.dispatchTransitionProgress(
|
|
45
|
+
0.0f,
|
|
46
|
+
isExitAnimation,
|
|
47
|
+
isExitAnimation,
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override fun onAnimationEnd(animation: Animator) {
|
|
53
|
+
if (currentState === LifecycleState.START_DISPATCHED) {
|
|
54
|
+
progressState()
|
|
55
|
+
animation.removeListener(this)
|
|
56
|
+
|
|
57
|
+
// wrapper.onViewAnimationEnd()
|
|
58
|
+
|
|
59
|
+
when (animationType) {
|
|
60
|
+
AnimationType.ENTER -> eventEmitter?.dispatchOnAppear()
|
|
61
|
+
AnimationType.EXIT -> eventEmitter?.dispatchOnDisappear()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
val isExitAnimation = animationType === AnimationType.EXIT
|
|
65
|
+
eventEmitter?.dispatchTransitionProgress(
|
|
66
|
+
1.0f,
|
|
67
|
+
isExitAnimation,
|
|
68
|
+
isExitAnimation,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
wrapper.screen.endRemovalTransition()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override fun onAnimationCancel(animation: Animator) = Unit
|
|
76
|
+
|
|
77
|
+
override fun onAnimationRepeat(animation: Animator) = Unit
|
|
78
|
+
|
|
79
|
+
private enum class LifecycleState {
|
|
80
|
+
INITIALIZED,
|
|
81
|
+
START_DISPATCHED,
|
|
82
|
+
END_DISPATCHED,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
companion object {
|
|
86
|
+
const val TAG = "ScreenEventDelegate"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.swmansion.rnscreens.events
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
4
|
+
import com.swmansion.rnscreens.Screen
|
|
5
|
+
import com.swmansion.rnscreens.ScreenFragment
|
|
6
|
+
|
|
7
|
+
// TODO: Consider taking weak ref here or accepting screen as argument in every method
|
|
8
|
+
// to avoid reference cycle.
|
|
9
|
+
class ScreenEventEmitter(val screen: Screen) {
|
|
10
|
+
val reactEventDispatcher
|
|
11
|
+
get() = screen.reactEventDispatcher
|
|
12
|
+
|
|
13
|
+
val reactSurfaceId
|
|
14
|
+
get() = UIManagerHelper.getSurfaceId(screen)
|
|
15
|
+
|
|
16
|
+
fun dispatchOnWillAppear() =
|
|
17
|
+
reactEventDispatcher?.dispatchEvent(ScreenWillAppearEvent(reactSurfaceId, screen.id))
|
|
18
|
+
|
|
19
|
+
fun dispatchOnAppear() =
|
|
20
|
+
reactEventDispatcher?.dispatchEvent(ScreenAppearEvent(reactSurfaceId, screen.id))
|
|
21
|
+
|
|
22
|
+
fun dispatchOnWillDisappear() =
|
|
23
|
+
reactEventDispatcher?.dispatchEvent(ScreenWillDisappearEvent(reactSurfaceId, screen.id))
|
|
24
|
+
|
|
25
|
+
fun dispatchOnDisappear() =
|
|
26
|
+
reactEventDispatcher?.dispatchEvent(ScreenDisappearEvent(reactSurfaceId, screen.id))
|
|
27
|
+
|
|
28
|
+
fun dispatchOnDismissed() =
|
|
29
|
+
reactEventDispatcher?.dispatchEvent(ScreenDismissedEvent(reactSurfaceId, screen.id))
|
|
30
|
+
|
|
31
|
+
fun dispatchTransitionProgress(progress: Float, isExitAnimation: Boolean, isGoingForward: Boolean) {
|
|
32
|
+
val sanitizedProgress = progress.coerceIn(0.0f, 1.0f)
|
|
33
|
+
val coalescingKey = ScreenFragment.getCoalescingKey(sanitizedProgress)
|
|
34
|
+
reactEventDispatcher?.dispatchEvent(ScreenTransitionProgressEvent(reactSurfaceId, screen.id, sanitizedProgress, isExitAnimation, isGoingForward, coalescingKey))
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -73,15 +73,30 @@ namespace react = facebook::react;
|
|
|
73
73
|
|
|
74
74
|
- (void)attachToAncestorScreenView
|
|
75
75
|
{
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
RNSScreen *_Nullable screen =
|
|
77
|
+
static_cast<RNSScreen *_Nullable>([[self findFirstScreenViewAncestor] reactViewController]);
|
|
78
|
+
if (screen == nil) {
|
|
79
|
+
RCTLogError(@"Failed to find parent screen controller from %@.", self);
|
|
78
80
|
return;
|
|
79
81
|
}
|
|
80
|
-
|
|
81
|
-
RNSScreen *screen = (RNSScreen *)[self.reactSuperview reactViewController];
|
|
82
82
|
[self attachToAncestorScreenViewStartingFrom:screen];
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
- (nullable RNSScreenView *)findFirstScreenViewAncestor
|
|
86
|
+
{
|
|
87
|
+
UIView *currentView = self;
|
|
88
|
+
|
|
89
|
+
// In standard scenario this should do only a single iteration.
|
|
90
|
+
// Haven't got repro, but we got reports that there are scenarios
|
|
91
|
+
// when there are intermediate views between screen view & the content wrapper.
|
|
92
|
+
// https://github.com/software-mansion/react-native-screens/pull/2683
|
|
93
|
+
do {
|
|
94
|
+
currentView = currentView.reactSuperview;
|
|
95
|
+
} while (currentView != nil && ![currentView isKindOfClass:RNSScreenView.class]);
|
|
96
|
+
|
|
97
|
+
return static_cast<RNSScreenView *_Nullable>(currentView);
|
|
98
|
+
}
|
|
99
|
+
|
|
85
100
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
86
101
|
|
|
87
102
|
#pragma mark - RCTComponentViewProtocol
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-screens",
|
|
3
|
-
"version": "4.7.0-beta.
|
|
3
|
+
"version": "4.7.0-beta.4",
|
|
4
4
|
"description": "Native navigation primitives for your React Native app.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"submodules": "git submodule update --init --recursive && (cd react-navigation && yarn && yarn build && cd ../)",
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
package com.swmansion.rnscreens.events
|
|
2
|
-
|
|
3
|
-
import android.animation.Animator
|
|
4
|
-
import com.swmansion.rnscreens.ScreenFragmentWrapper
|
|
5
|
-
|
|
6
|
-
class ScreenEventDelegate(
|
|
7
|
-
private val wrapper: ScreenFragmentWrapper,
|
|
8
|
-
) : Animator.AnimatorListener {
|
|
9
|
-
private var currentState: LifecycleState = LifecycleState.INITIALIZED
|
|
10
|
-
|
|
11
|
-
private fun progressState() {
|
|
12
|
-
currentState =
|
|
13
|
-
when (currentState) {
|
|
14
|
-
LifecycleState.INITIALIZED -> LifecycleState.START_DISPATCHED
|
|
15
|
-
LifecycleState.START_DISPATCHED -> LifecycleState.END_DISPATCHED
|
|
16
|
-
LifecycleState.END_DISPATCHED -> LifecycleState.END_DISPATCHED
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
override fun onAnimationStart(animation: Animator) {
|
|
21
|
-
if (currentState === LifecycleState.INITIALIZED) {
|
|
22
|
-
progressState()
|
|
23
|
-
wrapper.onViewAnimationStart()
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
override fun onAnimationEnd(animation: Animator) {
|
|
28
|
-
if (currentState === LifecycleState.START_DISPATCHED) {
|
|
29
|
-
progressState()
|
|
30
|
-
animation.removeListener(this)
|
|
31
|
-
wrapper.onViewAnimationEnd()
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
override fun onAnimationCancel(animation: Animator) = Unit
|
|
36
|
-
|
|
37
|
-
override fun onAnimationRepeat(animation: Animator) = Unit
|
|
38
|
-
|
|
39
|
-
private enum class LifecycleState {
|
|
40
|
-
INITIALIZED,
|
|
41
|
-
START_DISPATCHED,
|
|
42
|
-
END_DISPATCHED,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
companion object {
|
|
46
|
-
const val TAG = "ScreenEventDelegate"
|
|
47
|
-
}
|
|
48
|
-
}
|