react-native-screens 4.25.1 → 4.25.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.
- package/android/src/main/java/com/swmansion/rnscreens/Screen.kt +1 -1
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/CustomBottomNavigationView.kt +37 -0
- package/android/src/main/java/com/swmansion/rnscreens/gamma/tabs/container/TabsContainer.kt +63 -7
- package/package.json +1 -1
|
@@ -248,7 +248,7 @@ class Screen(
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
if (coordinatorLayoutDidChange) {
|
|
251
|
-
updateShadowNodeScreenSize(width, height, top)
|
|
251
|
+
updateShadowNodeScreenSize(width, height, top + translationY.toInt())
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
footer?.onParentLayout(coordinatorLayoutDidChange, left, top, right, bottom, container!!.height)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
package com.swmansion.rnscreens.gamma.tabs.container
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import com.google.android.material.bottomnavigation.BottomNavigationView
|
|
6
|
+
|
|
7
|
+
@SuppressLint("ViewConstructor") // Should not be restored & should only be constructed by us.
|
|
8
|
+
class CustomBottomNavigationView(
|
|
9
|
+
context: Context,
|
|
10
|
+
val container: TabsContainer,
|
|
11
|
+
) : BottomNavigationView(context) {
|
|
12
|
+
private var actionOrigin: TabsActionOrigin? = null
|
|
13
|
+
|
|
14
|
+
internal fun setSelectedItemIdWithActionOrigin(
|
|
15
|
+
itemId: Int,
|
|
16
|
+
actionOrigin: TabsActionOrigin,
|
|
17
|
+
) {
|
|
18
|
+
require(actionOrigin !== TabsActionOrigin.USER) {
|
|
19
|
+
"[RNScreens] User-triggered actions should be processed via regular setSelectedItemId callback"
|
|
20
|
+
}
|
|
21
|
+
this.actionOrigin = actionOrigin
|
|
22
|
+
selectedItemId = itemId
|
|
23
|
+
this.actionOrigin = null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override fun setSelectedItemId(itemId: Int) {
|
|
27
|
+
if (this.actionOrigin == null) {
|
|
28
|
+
this.actionOrigin = TabsActionOrigin.USER
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
val actionOrigin = checkNotNull(this.actionOrigin)
|
|
32
|
+
super.setSelectedItemId(itemId)
|
|
33
|
+
container.onAfterSetSelectedItemId(itemId, actionOrigin)
|
|
34
|
+
|
|
35
|
+
this.actionOrigin = null
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -109,8 +109,8 @@ class TabsContainer internal constructor(
|
|
|
109
109
|
R.style.Theme_Material3_DayNight_NoActionBar,
|
|
110
110
|
)
|
|
111
111
|
|
|
112
|
-
internal val bottomNavigationView:
|
|
113
|
-
|
|
112
|
+
internal val bottomNavigationView: CustomBottomNavigationView =
|
|
113
|
+
CustomBottomNavigationView(themedContext, this).apply {
|
|
114
114
|
layoutParams =
|
|
115
115
|
LayoutParams(
|
|
116
116
|
LayoutParams.MATCH_PARENT,
|
|
@@ -256,6 +256,16 @@ class TabsContainer internal constructor(
|
|
|
256
256
|
setPendingNavigationStateUpdate(null)
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
internal fun onAfterSetSelectedItemId(
|
|
260
|
+
itemId: Int,
|
|
261
|
+
actionOrigin: TabsActionOrigin,
|
|
262
|
+
) {
|
|
263
|
+
if (actionOrigin === TabsActionOrigin.USER) {
|
|
264
|
+
// For non-user actions these will be performed in [performContainerUpdate]
|
|
265
|
+
performPostSelectedTabUpdateActions()
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
259
269
|
// endregion
|
|
260
270
|
|
|
261
271
|
// region View lifecycle / insets / appearance
|
|
@@ -406,27 +416,62 @@ class TabsContainer internal constructor(
|
|
|
406
416
|
|
|
407
417
|
// region Private helpers
|
|
408
418
|
|
|
419
|
+
/**
|
|
420
|
+
* This is where programmatic update flow starts.
|
|
421
|
+
* This includes any JS-triggered action (navigation state update, prop update, etc.)
|
|
422
|
+
* and native programmatic actions - tab change.
|
|
423
|
+
*
|
|
424
|
+
* This method is supposed to perform all the necessary steps, satisfying all invalidation
|
|
425
|
+
* signals in a coordinated manner.
|
|
426
|
+
*
|
|
427
|
+
* The update actions are split into three phases: pre-, selection change, and post-.
|
|
428
|
+
* Pre-selection actions are run only here, in programmatic flow. This is not a hard requirement,
|
|
429
|
+
* it is just not needed now.
|
|
430
|
+
*
|
|
431
|
+
* Post-selection actions are performed here or in parallel flow triggered on user selection.
|
|
432
|
+
*
|
|
433
|
+
* The selected tab update takes place here only for programmatic changes.
|
|
434
|
+
* User triggered changes have separate entry-point.
|
|
435
|
+
*/
|
|
409
436
|
private fun performContainerUpdate() {
|
|
437
|
+
performPreSelectedTabUpdateActions()
|
|
438
|
+
performSelectedTabUpdateIfNeeded()
|
|
439
|
+
performPostSelectedTabUpdateActions()
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
private fun performPreSelectedTabUpdateActions() {
|
|
443
|
+
updateNavigationMenuStructureIfNeeded()
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
private fun performPostSelectedTabUpdateActions() {
|
|
447
|
+
updateBottomNavigationViewAppearanceIfNeeded()
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private fun updateNavigationMenuStructureIfNeeded() {
|
|
410
451
|
if (invalidationFlags.isNavigationMenuStructureInvalidated) {
|
|
411
452
|
invalidationFlags.isNavigationMenuStructureInvalidated = false
|
|
412
453
|
updateNavigationMenuStructure()
|
|
413
454
|
}
|
|
455
|
+
}
|
|
414
456
|
|
|
457
|
+
private fun performSelectedTabUpdateIfNeeded() {
|
|
415
458
|
if (invalidationFlags.isSelectedTabInvalidated) {
|
|
416
459
|
invalidationFlags.isSelectedTabInvalidated = false
|
|
417
|
-
|
|
460
|
+
performSelectedTabUpdate()
|
|
418
461
|
}
|
|
462
|
+
}
|
|
419
463
|
|
|
464
|
+
private fun updateBottomNavigationViewAppearanceIfNeeded() {
|
|
420
465
|
if (invalidationFlags.isNavigationMenuAppearanceInvalidated) {
|
|
421
466
|
invalidationFlags.isNavigationMenuAppearanceInvalidated = false
|
|
422
|
-
|
|
467
|
+
updateBottomNavigationViewAppearance()
|
|
423
468
|
a11yCoordinator.setA11yPropertiesToAllTabItems()
|
|
424
469
|
}
|
|
425
470
|
}
|
|
426
471
|
|
|
427
|
-
private fun
|
|
472
|
+
private fun performSelectedTabUpdate() {
|
|
428
473
|
if (pendingStateUpdateRequest == null) {
|
|
429
|
-
RNSLog.w(TAG, "TabsContainer::
|
|
474
|
+
RNSLog.w(TAG, "TabsContainer::performSelectedTabUpdate called w/o pending operation; skipping update")
|
|
430
475
|
return
|
|
431
476
|
}
|
|
432
477
|
|
|
@@ -450,7 +495,7 @@ class TabsContainer internal constructor(
|
|
|
450
495
|
if (bottomNavigationView.selectedItemId != nextSelectedMenuItemId || navState.isEmpty()) {
|
|
451
496
|
isInExternalOperationContext = true
|
|
452
497
|
// This triggers on OnMenuItemClicked callback, where we perform actual update from
|
|
453
|
-
bottomNavigationView.
|
|
498
|
+
bottomNavigationView.setSelectedItemIdWithActionOrigin(nextSelectedMenuItemId, stateUpdateRequest.actionOrigin)
|
|
454
499
|
isInExternalOperationContext = false
|
|
455
500
|
} else {
|
|
456
501
|
observerRegistry.emitOnNavigationStateUpdateRejected(
|
|
@@ -559,6 +604,13 @@ class TabsContainer internal constructor(
|
|
|
559
604
|
val hasTriggeredSpecialEffect =
|
|
560
605
|
if (isRepeated) specialEffectsHandler.handleRepeatedTabSelection() else false
|
|
561
606
|
|
|
607
|
+
if (stateChanged && !isRepeated) {
|
|
608
|
+
// If we've effectively changed the tab, we need to raise appropriate flags.
|
|
609
|
+
// This line assumes that any required e.g. appearance actions will be performed
|
|
610
|
+
// synchronously later in the flow.
|
|
611
|
+
invalidationFlags.invalidateOnSelectedTabChanged()
|
|
612
|
+
}
|
|
613
|
+
|
|
562
614
|
if (stateChanged) {
|
|
563
615
|
observerRegistry.emitOnNavigationStateUpdate(
|
|
564
616
|
navState,
|
|
@@ -694,4 +746,8 @@ internal class TabsContainerInvalidationFlags(
|
|
|
694
746
|
isNavigationMenuAppearanceInvalidated = true
|
|
695
747
|
isNavigationMenuStructureInvalidated = true
|
|
696
748
|
}
|
|
749
|
+
|
|
750
|
+
internal fun invalidateOnSelectedTabChanged() {
|
|
751
|
+
isNavigationMenuAppearanceInvalidated = true
|
|
752
|
+
}
|
|
697
753
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-screens",
|
|
3
|
-
"version": "4.25.
|
|
3
|
+
"version": "4.25.2",
|
|
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 ../)",
|