Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package com.swmansion.rnscreens.gamma.tabs

import android.R
import com.swmansion.rnscreens.R
import android.content.res.ColorStateList
import android.util.Log
import android.view.Choreographer
import android.view.Menu
import android.view.MenuItem
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.view.children
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import com.facebook.react.common.assets.ReactFontManager
import com.facebook.react.modules.core.ReactChoreographer
import com.facebook.react.uimanager.ThemedReactContext
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.navigation.NavigationBarView
Expand Down Expand Up @@ -90,7 +93,7 @@ class TabsHost(
private val containerUpdateCoordinator = ContainerUpdateCoordinator()

private val bottomNavigationView: BottomNavigationView =
BottomNavigationView(reactContext).apply {
BottomNavigationView(ContextThemeWrapper(reactContext, R.style.custom)).apply {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
}

Expand All @@ -115,7 +118,7 @@ class TabsHost(

private val tabScreenFragments: MutableList<TabScreenFragment> = arrayListOf()

private var isLayoutInvalidated: Boolean = false
private var isLayoutEnqueued: Boolean = false

var tabBarBackgroundColor: Int? by Delegates.observable<Int?>(null) { _, oldValue, newValue ->
updateNavigationMenuIfNeeded(oldValue, newValue)
Expand Down Expand Up @@ -279,7 +282,7 @@ class TabsHost(
tabBarBackgroundColor ?: com.google.android.material.R.color.m3_sys_color_light_surface_container,
)

val states = arrayOf(intArrayOf(-R.attr.state_checked), intArrayOf(R.attr.state_checked))
val states = arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked))

// Font color
val fontInactiveColor = tabBarItemTitleFontColor ?: com.google.android.material.R.color.m3_tabs_text_color_secondary
Expand Down Expand Up @@ -317,7 +320,7 @@ class TabsHost(
checkNotNull(getSelectedTabScreenFragmentId()) { "[RNScreens] A single selected tab must be present" }

post {
forceSubtreeMeasureAndLayoutPass()
refreshLayout()
Log.d(TAG, "BottomNavigationView request layout")
}
}
Expand Down Expand Up @@ -388,9 +391,27 @@ class TabsHost(
}
}

private fun forceSubtreeMeasureAndLayoutPass() {
isLayoutInvalidated = false
private val layoutCallback = Choreographer.FrameCallback {
isLayoutEnqueued = false
forceSubtreeMeasureAndLayoutPass()
}

private fun refreshLayout() {
@Suppress("SENSELESS_COMPARISON") // layoutCallback can be null here since this method can be called in init
if (!isLayoutEnqueued && layoutCallback != null) {
isLayoutEnqueued = true
// we use NATIVE_ANIMATED_MODULE choreographer queue because it allows us to catch the current
// looper loop instead of enqueueing the update in the next loop causing a one frame delay.
ReactChoreographer
.getInstance()
.postFrameCallback(
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE,
layoutCallback
)
}
}

private fun forceSubtreeMeasureAndLayoutPass() {
measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
Expand Down
7 changes: 7 additions & 0 deletions android/src/main/res/base/values/themes.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base application theme. -->
<style name="custom" parent="Theme.Material3.DayNight.NoActionBar">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<style name="custom" parent="Theme.Material3.DayNight.NoActionBar">
<style name="material_base" parent="Theme.Material3.DayNight.NoActionBar">

or something more informative.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed that in #3026 anyway

<!-- Customize your theme here. -->
</style>
</resources>
1 change: 1 addition & 0 deletions apps/src/tests/TestBottomTabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const TAB_CONFIGS: TabConfiguration[] = [
selectedIcon: {
sfSymbolName: 'rectangle.stack.fill',
},
iconResourceName: 'sym_action_chat', // Android specific
title: 'Tab4',
},
contentViewRenderFn: Tab4,
Expand Down
Loading