diff --git a/android/src/main/java/com/rcttabview/RCTTabView.kt b/android/src/main/java/com/rcttabview/RCTTabView.kt
index e4f31bf..c47bc29 100644
--- a/android/src/main/java/com/rcttabview/RCTTabView.kt
+++ b/android/src/main/java/com/rcttabview/RCTTabView.kt
@@ -4,10 +4,13 @@ import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
+import android.util.TypedValue
import android.net.Uri
import android.view.Choreographer
import android.view.MenuItem
+import androidx.appcompat.content.res.AppCompatResources
import com.facebook.common.references.CloseableReference
import com.facebook.datasource.DataSources
import com.facebook.drawee.backends.pipeline.Fresco
@@ -146,4 +149,23 @@ class ReactBottomNavigationView(context: Context) : BottomNavigationView(context
super.onDetachedFromWindow()
isAnimating = false
}
+
+ fun setBarTintColor(color: Int?) {
+ // Set the color, either using the active background color or a default color.
+ val backgroundColor = color ?: getDefaultColorFor(android.R.attr.colorPrimary) ?: return
+
+ // Apply the same color to both active and inactive states
+ val colorDrawable = ColorDrawable(backgroundColor)
+
+ itemBackground = colorDrawable
+ }
+
+ private fun getDefaultColorFor(baseColorThemeAttr: Int): Int? {
+ val value = TypedValue()
+ if (!context.theme.resolveAttribute(baseColorThemeAttr, value, true)) {
+ return null
+ }
+ val baseColor = AppCompatResources.getColorStateList(context, value.resourceId)
+ return baseColor.defaultColor
+ }
}
diff --git a/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt b/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt
index d1495b8..ed374c8 100644
--- a/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt
+++ b/android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt
@@ -68,6 +68,11 @@ class RCTTabViewViewManager :
view.setIcons(icons)
}
+ @ReactProp(name = "barTintColor")
+ fun setBarTintColor(view: ReactBottomNavigationView, color: Int?) {
+ view.setBarTintColor(color)
+ }
+
@ReactProp(name = "rippleColor")
fun setRippleColor(view: ReactBottomNavigationView, rippleColor: Int?) {
if (rippleColor != null) {
diff --git a/docs/docs/docs/guides/usage-with-react-navigation.mdx b/docs/docs/docs/guides/usage-with-react-navigation.mdx
index 811e7c1..ebe5f25 100644
--- a/docs/docs/docs/guides/usage-with-react-navigation.mdx
+++ b/docs/docs/docs/guides/usage-with-react-navigation.mdx
@@ -65,6 +65,10 @@ Whether to disable page animations between tabs.
Describes the appearance attributes for the tabBar to use when an observable scroll view is scrolled to the bottom.
+#### `barTintColor`
+
+Background color of the tab bar.
+
#### `translucent`
A Boolean value that indicates whether the tab bar is translucent.
diff --git a/example/src/App.tsx b/example/src/App.tsx
index bc97be0..647c574 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -39,6 +39,10 @@ const FourTabsTransparentScrollEdgeAppearance = () => {
return ;
};
+const FourTabsWithBarTintColor = () => {
+ return ;
+};
+
const FourTabsTranslucent = () => {
return ;
};
@@ -62,6 +66,10 @@ const examples = [
component: FourTabsTransparentScrollEdgeAppearance,
name: 'Four Tabs - Transparent scroll edge appearance',
},
+ {
+ component: FourTabsWithBarTintColor,
+ name: 'Four Tabs - Custom Background Color of Tabs',
+ },
{
component: FourTabsTranslucent,
name: 'Four Tabs - Translucent tab bar',
diff --git a/example/src/Examples/FourTabs.tsx b/example/src/Examples/FourTabs.tsx
index c6ceceb..5c474c7 100644
--- a/example/src/Examples/FourTabs.tsx
+++ b/example/src/Examples/FourTabs.tsx
@@ -10,6 +10,7 @@ interface Props {
ignoresTopSafeArea?: boolean;
disablePageAnimations?: boolean;
scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent';
+ barTintColor?: ColorValue;
translucent?: boolean;
rippleColor?: ColorValue;
}
@@ -18,6 +19,7 @@ export default function FourTabs({
ignoresTopSafeArea = false,
disablePageAnimations = false,
scrollEdgeAppearance = 'default',
+ barTintColor,
translucent = true,
rippleColor,
}: Props) {
@@ -64,6 +66,7 @@ export default function FourTabs({
navigationState={{ index, routes }}
onIndexChange={setIndex}
renderScene={renderScene}
+ barTintColor={barTintColor}
translucent={translucent}
rippleColor={rippleColor}
/>
diff --git a/ios/RCTTabViewViewManager.mm b/ios/RCTTabViewViewManager.mm
index c4acb2a..6ca85e8 100644
--- a/ios/RCTTabViewViewManager.mm
+++ b/ios/RCTTabViewViewManager.mm
@@ -32,6 +32,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(ignoresTopSafeArea, BOOL)
RCT_EXPORT_VIEW_PROPERTY(disablePageAnimations, BOOL)
RCT_EXPORT_VIEW_PROPERTY(scrollEdgeAppearance, NSString)
+RCT_EXPORT_VIEW_PROPERTY(barTintColor, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(translucent, BOOL)
@end
diff --git a/ios/TabViewImpl.swift b/ios/TabViewImpl.swift
index 4c844b0..571fb40 100644
--- a/ios/TabViewImpl.swift
+++ b/ios/TabViewImpl.swift
@@ -15,6 +15,7 @@ class TabViewProps: ObservableObject {
@Published var ignoresTopSafeArea: Bool?
@Published var disablePageAnimations: Bool = false
@Published var scrollEdgeAppearance: String?
+ @Published var barTintColor: UIColor?
@Published var translucent: Bool = true
}
@@ -63,7 +64,6 @@ struct TabViewImpl: View {
}
}
.getSidebarAdaptable(enabled: props.sidebarAdaptable ?? false)
- .tabBarTranslucent(props.translucent)
.onChange(of: props.selectedPage ?? "") { newValue in
if (props.disablePageAnimations) {
UIView.setAnimationsEnabled(false)
@@ -73,16 +73,22 @@ struct TabViewImpl: View {
}
onSelect(newValue)
}
+ .onAppear() {
+ updateTabBarAppearance(props: props)
+ }
+ .onChange(of: props.barTintColor) { newValue in
+ updateTabBarAppearance(props: props)
+ }
.onChange(of: props.scrollEdgeAppearance) { newValue in
- if #available(iOS 15.0, *) {
- UITabBar.appearance().scrollEdgeAppearance = configureAppearance(for: newValue ?? "")
- }
+ updateTabBarAppearance(props: props)
+ }
+ .onChange(of: props.translucent) { newValue in
+ updateTabBarAppearance(props: props)
}
}
}
-private func configureAppearance(for appearanceType: String) -> UITabBarAppearance {
- let appearance = UITabBarAppearance()
+private func configureAppearance(for appearanceType: String, appearance: UITabBarAppearance) -> UITabBarAppearance {
switch appearanceType {
case "opaque":
@@ -96,6 +102,27 @@ private func configureAppearance(for appearanceType: String) -> UITabBarAppearan
return appearance
}
+private func updateTabBarAppearance(props: TabViewProps) {
+ if #available(iOS 15.0, *) {
+ let appearance = UITabBarAppearance()
+
+ UITabBar.appearance().scrollEdgeAppearance = configureAppearance(for: props.scrollEdgeAppearance ?? "", appearance: appearance)
+
+ if props.translucent == false {
+ appearance.configureWithOpaqueBackground()
+ }
+
+ if props.barTintColor != nil {
+ appearance.backgroundColor = props.barTintColor
+ }
+
+ UITabBar.appearance().standardAppearance = appearance
+ } else {
+ UITabBar.appearance().barTintColor = props.barTintColor
+ UITabBar.appearance().isTranslucent = props.translucent
+ }
+}
+
struct TabItem: View {
var title: String?
var icon: UIImage?
@@ -159,15 +186,4 @@ extension View {
.frame(idealWidth: frame.width, idealHeight: frame.height)
}
}
-
- @ViewBuilder
- func tabBarTranslucent(_ translucent: Bool) -> some View {
- self
- .onAppear {
- UITabBar.appearance().isTranslucent = translucent
- }
- .onChange(of: translucent) { newValue in
- UITabBar.appearance().isTranslucent = newValue
- }
- }
}
diff --git a/ios/TabViewProvider.swift b/ios/TabViewProvider.swift
index 5caf4f7..6349042 100644
--- a/ios/TabViewProvider.swift
+++ b/ios/TabViewProvider.swift
@@ -76,6 +76,12 @@ struct TabData: Codable {
props.items = parseTabData(from: items)
}
}
+
+ @objc var barTintColor: NSNumber? {
+ didSet {
+ props.barTintColor = RCTConvert.uiColor(barTintColor)
+ }
+ }
@objc public convenience init(eventDispatcher: RCTEventDispatcherProtocol, imageLoader: RCTImageLoader) {
self.init()
diff --git a/src/TabView.tsx b/src/TabView.tsx
index 3cc0182..005ae02 100644
--- a/src/TabView.tsx
+++ b/src/TabView.tsx
@@ -85,6 +85,10 @@ interface Props {
focused: boolean;
}) => ImageSource | undefined;
+ /**
+ * Background color of the tab bar.
+ */
+ barTintColor?: ColorValue;
/**
* A Boolean value that indicates whether the tab bar is translucent. (iOS only)
*/
@@ -106,6 +110,7 @@ const TabView = ({
? route.focusedIcon
: route.unfocusedIcon
: route.focusedIcon,
+ barTintColor,
...props
}: Props) => {
// @ts-ignore
@@ -192,6 +197,7 @@ const TabView = ({
onPageSelected={({ nativeEvent: { key } }) => {
jumpTo(key);
}}
+ barTintColor={processColor(barTintColor)}
{...props}
rippleColor={processColor(props.rippleColor)}
>
diff --git a/src/TabViewNativeComponent.ts b/src/TabViewNativeComponent.ts
index a442c8a..f7a44ee 100644
--- a/src/TabViewNativeComponent.ts
+++ b/src/TabViewNativeComponent.ts
@@ -23,6 +23,7 @@ export interface TabViewProps extends ViewProps {
labeled?: boolean;
sidebarAdaptable?: boolean;
scrollEdgeAppearance?: string;
+ barTintColor?: ProcessedColorValue | null;
translucent?: boolean;
rippleColor?: ProcessedColorValue | null;
}