Skip to content

Commit 6a2f41b

Browse files
Added support for barTintColor in android ios (#55)
* feat: added support for bar tint color on android ios * fix: added color in example * fix: pr comments resovled android * fix: pr comments resovled android * feat: refactored code
1 parent 1f5db7b commit 6a2f41b

File tree

10 files changed

+89
-17
lines changed

10 files changed

+89
-17
lines changed

android/src/main/java/com/rcttabview/RCTTabView.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import android.content.Context
44
import android.content.res.ColorStateList
55
import android.graphics.Color
66
import android.graphics.drawable.BitmapDrawable
7+
import android.graphics.drawable.ColorDrawable
78
import android.graphics.drawable.Drawable
9+
import android.util.TypedValue
810
import android.net.Uri
911
import android.view.Choreographer
1012
import android.view.MenuItem
13+
import androidx.appcompat.content.res.AppCompatResources
1114
import com.facebook.common.references.CloseableReference
1215
import com.facebook.datasource.DataSources
1316
import com.facebook.drawee.backends.pipeline.Fresco
@@ -146,4 +149,23 @@ class ReactBottomNavigationView(context: Context) : BottomNavigationView(context
146149
super.onDetachedFromWindow()
147150
isAnimating = false
148151
}
152+
153+
fun setBarTintColor(color: Int?) {
154+
// Set the color, either using the active background color or a default color.
155+
val backgroundColor = color ?: getDefaultColorFor(android.R.attr.colorPrimary) ?: return
156+
157+
// Apply the same color to both active and inactive states
158+
val colorDrawable = ColorDrawable(backgroundColor)
159+
160+
itemBackground = colorDrawable
161+
}
162+
163+
private fun getDefaultColorFor(baseColorThemeAttr: Int): Int? {
164+
val value = TypedValue()
165+
if (!context.theme.resolveAttribute(baseColorThemeAttr, value, true)) {
166+
return null
167+
}
168+
val baseColor = AppCompatResources.getColorStateList(context, value.resourceId)
169+
return baseColor.defaultColor
170+
}
149171
}

android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ class RCTTabViewViewManager :
6868
view.setIcons(icons)
6969
}
7070

71+
@ReactProp(name = "barTintColor")
72+
fun setBarTintColor(view: ReactBottomNavigationView, color: Int?) {
73+
view.setBarTintColor(color)
74+
}
75+
7176
@ReactProp(name = "rippleColor")
7277
fun setRippleColor(view: ReactBottomNavigationView, rippleColor: Int?) {
7378
if (rippleColor != null) {

docs/docs/docs/guides/usage-with-react-navigation.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ Whether to disable page animations between tabs.
6565

6666
Describes the appearance attributes for the tabBar to use when an observable scroll view is scrolled to the bottom.
6767

68+
#### `barTintColor`
69+
70+
Background color of the tab bar.
71+
6872
#### `translucent` <Badge text="iOS" type="info" />
6973

7074
A Boolean value that indicates whether the tab bar is translucent.

example/src/App.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ const FourTabsTransparentScrollEdgeAppearance = () => {
3939
return <FourTabs scrollEdgeAppearance="transparent" />;
4040
};
4141

42+
const FourTabsWithBarTintColor = () => {
43+
return <FourTabs barTintColor={'#87CEEB'} />;
44+
};
45+
4246
const FourTabsTranslucent = () => {
4347
return <FourTabs translucent={false} />;
4448
};
@@ -62,6 +66,10 @@ const examples = [
6266
component: FourTabsTransparentScrollEdgeAppearance,
6367
name: 'Four Tabs - Transparent scroll edge appearance',
6468
},
69+
{
70+
component: FourTabsWithBarTintColor,
71+
name: 'Four Tabs - Custom Background Color of Tabs',
72+
},
6573
{
6674
component: FourTabsTranslucent,
6775
name: 'Four Tabs - Translucent tab bar',

example/src/Examples/FourTabs.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface Props {
1010
ignoresTopSafeArea?: boolean;
1111
disablePageAnimations?: boolean;
1212
scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent';
13+
barTintColor?: ColorValue;
1314
translucent?: boolean;
1415
rippleColor?: ColorValue;
1516
}
@@ -18,6 +19,7 @@ export default function FourTabs({
1819
ignoresTopSafeArea = false,
1920
disablePageAnimations = false,
2021
scrollEdgeAppearance = 'default',
22+
barTintColor,
2123
translucent = true,
2224
rippleColor,
2325
}: Props) {
@@ -64,6 +66,7 @@ export default function FourTabs({
6466
navigationState={{ index, routes }}
6567
onIndexChange={setIndex}
6668
renderScene={renderScene}
69+
barTintColor={barTintColor}
6770
translucent={translucent}
6871
rippleColor={rippleColor}
6972
/>

ios/RCTTabViewViewManager.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ - (UIView *)view
3232
RCT_EXPORT_VIEW_PROPERTY(ignoresTopSafeArea, BOOL)
3333
RCT_EXPORT_VIEW_PROPERTY(disablePageAnimations, BOOL)
3434
RCT_EXPORT_VIEW_PROPERTY(scrollEdgeAppearance, NSString)
35+
RCT_EXPORT_VIEW_PROPERTY(barTintColor, NSNumber)
3536
RCT_EXPORT_VIEW_PROPERTY(translucent, BOOL)
3637

3738
@end

ios/TabViewImpl.swift

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class TabViewProps: ObservableObject {
1515
@Published var ignoresTopSafeArea: Bool?
1616
@Published var disablePageAnimations: Bool = false
1717
@Published var scrollEdgeAppearance: String?
18+
@Published var barTintColor: UIColor?
1819
@Published var translucent: Bool = true
1920
}
2021

@@ -63,7 +64,6 @@ struct TabViewImpl: View {
6364
}
6465
}
6566
.getSidebarAdaptable(enabled: props.sidebarAdaptable ?? false)
66-
.tabBarTranslucent(props.translucent)
6767
.onChange(of: props.selectedPage ?? "") { newValue in
6868
if (props.disablePageAnimations) {
6969
UIView.setAnimationsEnabled(false)
@@ -73,16 +73,22 @@ struct TabViewImpl: View {
7373
}
7474
onSelect(newValue)
7575
}
76+
.onAppear() {
77+
updateTabBarAppearance(props: props)
78+
}
79+
.onChange(of: props.barTintColor) { newValue in
80+
updateTabBarAppearance(props: props)
81+
}
7682
.onChange(of: props.scrollEdgeAppearance) { newValue in
77-
if #available(iOS 15.0, *) {
78-
UITabBar.appearance().scrollEdgeAppearance = configureAppearance(for: newValue ?? "")
79-
}
83+
updateTabBarAppearance(props: props)
84+
}
85+
.onChange(of: props.translucent) { newValue in
86+
updateTabBarAppearance(props: props)
8087
}
8188
}
8289
}
8390

84-
private func configureAppearance(for appearanceType: String) -> UITabBarAppearance {
85-
let appearance = UITabBarAppearance()
91+
private func configureAppearance(for appearanceType: String, appearance: UITabBarAppearance) -> UITabBarAppearance {
8692

8793
switch appearanceType {
8894
case "opaque":
@@ -96,6 +102,27 @@ private func configureAppearance(for appearanceType: String) -> UITabBarAppearan
96102
return appearance
97103
}
98104

105+
private func updateTabBarAppearance(props: TabViewProps) {
106+
if #available(iOS 15.0, *) {
107+
let appearance = UITabBarAppearance()
108+
109+
UITabBar.appearance().scrollEdgeAppearance = configureAppearance(for: props.scrollEdgeAppearance ?? "", appearance: appearance)
110+
111+
if props.translucent == false {
112+
appearance.configureWithOpaqueBackground()
113+
}
114+
115+
if props.barTintColor != nil {
116+
appearance.backgroundColor = props.barTintColor
117+
}
118+
119+
UITabBar.appearance().standardAppearance = appearance
120+
} else {
121+
UITabBar.appearance().barTintColor = props.barTintColor
122+
UITabBar.appearance().isTranslucent = props.translucent
123+
}
124+
}
125+
99126
struct TabItem: View {
100127
var title: String?
101128
var icon: UIImage?
@@ -159,15 +186,4 @@ extension View {
159186
.frame(idealWidth: frame.width, idealHeight: frame.height)
160187
}
161188
}
162-
163-
@ViewBuilder
164-
func tabBarTranslucent(_ translucent: Bool) -> some View {
165-
self
166-
.onAppear {
167-
UITabBar.appearance().isTranslucent = translucent
168-
}
169-
.onChange(of: translucent) { newValue in
170-
UITabBar.appearance().isTranslucent = newValue
171-
}
172-
}
173189
}

ios/TabViewProvider.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ struct TabData: Codable {
7676
props.items = parseTabData(from: items)
7777
}
7878
}
79+
80+
@objc var barTintColor: NSNumber? {
81+
didSet {
82+
props.barTintColor = RCTConvert.uiColor(barTintColor)
83+
}
84+
}
7985

8086
@objc public convenience init(eventDispatcher: RCTEventDispatcherProtocol, imageLoader: RCTImageLoader) {
8187
self.init()

src/TabView.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ interface Props<Route extends BaseRoute> {
8585
focused: boolean;
8686
}) => ImageSource | undefined;
8787

88+
/**
89+
* Background color of the tab bar.
90+
*/
91+
barTintColor?: ColorValue;
8892
/**
8993
* A Boolean value that indicates whether the tab bar is translucent. (iOS only)
9094
*/
@@ -106,6 +110,7 @@ const TabView = <Route extends BaseRoute>({
106110
? route.focusedIcon
107111
: route.unfocusedIcon
108112
: route.focusedIcon,
113+
barTintColor,
109114
...props
110115
}: Props<Route>) => {
111116
// @ts-ignore
@@ -192,6 +197,7 @@ const TabView = <Route extends BaseRoute>({
192197
onPageSelected={({ nativeEvent: { key } }) => {
193198
jumpTo(key);
194199
}}
200+
barTintColor={processColor(barTintColor)}
195201
{...props}
196202
rippleColor={processColor(props.rippleColor)}
197203
>

src/TabViewNativeComponent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export interface TabViewProps extends ViewProps {
2323
labeled?: boolean;
2424
sidebarAdaptable?: boolean;
2525
scrollEdgeAppearance?: string;
26+
barTintColor?: ProcessedColorValue | null;
2627
translucent?: boolean;
2728
rippleColor?: ProcessedColorValue | null;
2829
}

0 commit comments

Comments
 (0)