Skip to content

Commit

Permalink
Added support for barTintColor in android ios (#55)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
shubhamguptadream11 authored Oct 21, 2024
1 parent 1f5db7b commit 6a2f41b
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 17 deletions.
22 changes: 22 additions & 0 deletions android/src/main/java/com/rcttabview/RCTTabView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}
5 changes: 5 additions & 0 deletions android/src/main/java/com/rcttabview/RCTTabViewViewManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/docs/guides/usage-with-react-navigation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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` <Badge text="iOS" type="info" />

A Boolean value that indicates whether the tab bar is translucent.
Expand Down
8 changes: 8 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ const FourTabsTransparentScrollEdgeAppearance = () => {
return <FourTabs scrollEdgeAppearance="transparent" />;
};

const FourTabsWithBarTintColor = () => {
return <FourTabs barTintColor={'#87CEEB'} />;
};

const FourTabsTranslucent = () => {
return <FourTabs translucent={false} />;
};
Expand All @@ -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',
Expand Down
3 changes: 3 additions & 0 deletions example/src/Examples/FourTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface Props {
ignoresTopSafeArea?: boolean;
disablePageAnimations?: boolean;
scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent';
barTintColor?: ColorValue;
translucent?: boolean;
rippleColor?: ColorValue;
}
Expand All @@ -18,6 +19,7 @@ export default function FourTabs({
ignoresTopSafeArea = false,
disablePageAnimations = false,
scrollEdgeAppearance = 'default',
barTintColor,
translucent = true,
rippleColor,
}: Props) {
Expand Down Expand Up @@ -64,6 +66,7 @@ export default function FourTabs({
navigationState={{ index, routes }}
onIndexChange={setIndex}
renderScene={renderScene}
barTintColor={barTintColor}
translucent={translucent}
rippleColor={rippleColor}
/>
Expand Down
1 change: 1 addition & 0 deletions ios/RCTTabViewViewManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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
50 changes: 33 additions & 17 deletions ios/TabViewImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
Expand All @@ -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":
Expand All @@ -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?
Expand Down Expand Up @@ -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
}
}
}
6 changes: 6 additions & 0 deletions ios/TabViewProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 6 additions & 0 deletions src/TabView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ interface Props<Route extends BaseRoute> {
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)
*/
Expand All @@ -106,6 +110,7 @@ const TabView = <Route extends BaseRoute>({
? route.focusedIcon
: route.unfocusedIcon
: route.focusedIcon,
barTintColor,
...props
}: Props<Route>) => {
// @ts-ignore
Expand Down Expand Up @@ -192,6 +197,7 @@ const TabView = <Route extends BaseRoute>({
onPageSelected={({ nativeEvent: { key } }) => {
jumpTo(key);
}}
barTintColor={processColor(barTintColor)}
{...props}
rippleColor={processColor(props.rippleColor)}
>
Expand Down
1 change: 1 addition & 0 deletions src/TabViewNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface TabViewProps extends ViewProps {
labeled?: boolean;
sidebarAdaptable?: boolean;
scrollEdgeAppearance?: string;
barTintColor?: ProcessedColorValue | null;
translucent?: boolean;
rippleColor?: ProcessedColorValue | null;
}
Expand Down

0 comments on commit 6a2f41b

Please sign in to comment.