Skip to content

Commit 55253ba

Browse files
committed
chore: support iconRenderingMode on Android
1 parent 748f3cb commit 55253ba

8 files changed

Lines changed: 25 additions & 14 deletions

File tree

.changeset/calm-icons-preserve.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
'@bottom-tabs/react-navigation': minor
44
---
55

6-
Add an iOS icon rendering mode option for preserving original colors of multicolor tab icons.
6+
Add an icon rendering mode option for preserving original colors of tab icons.

apps/example/src/Examples/OriginalIconColors.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ export default function OriginalIconColors() {
4646
navigationState={{ index, routes }}
4747
onIndexChange={setIndex}
4848
renderScene={renderScene}
49-
experimental_bakedTintColors
50-
tabBarActiveTintColor="blue"
51-
tabBarInactiveTintColor="purple"
5249
/>
5350
);
5451
}

docs/docs/docs/guides/standalone-usage.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ Each route in the `routes` array can have the following properties:
236236
- `title`: Display title for the tab
237237
- `focusedIcon`: Icon to show when tab is active
238238
- `unfocusedIcon`: Icon to show when tab is inactive (optional)
239-
- `iconRenderingMode`: Rendering mode for icons. Use `'alwaysOriginal'` on iOS to preserve multicolor icons instead of applying the native tab tint.
239+
- `iconRenderingMode`: Rendering mode for icons. Use `'alwaysOriginal'` to preserve multicolor icons instead of applying the native tab tint.
240240
- `badge`: Badge text to display on the tab
241241
- `activeTintColor`: Custom active tint color for this specific tab
242242
- `lazy`: Whether to lazy load this tab's content
@@ -281,14 +281,14 @@ Function to get the icon for a tab.
281281

282282
- Default: Uses `route.focusedIcon` and `route.unfocusedIcon`
283283

284-
#### `getIconRenderingMode` <Badge text="iOS" type="info" />
284+
#### `getIconRenderingMode`
285285

286286
Function to get the rendering mode for an image icon.
287287

288288
- Default: Uses `route.iconRenderingMode`
289289
- Options: `'automatic' | 'alwaysOriginal'`
290290

291-
Use `alwaysOriginal` to preserve the original colors of multicolor image icons, such as logos or branded assets, instead of applying the native iOS tab tint.
291+
Use `alwaysOriginal` to preserve the original colors of multicolor image icons, such as logos or branded assets, instead of applying the native tab tint.
292292

293293
#### `getHidden`
294294

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,14 +286,14 @@ Function that given `{ focused: boolean }` returns `ImageSource` or `AppleIcon`
286286
SF Symbols are only supported on Apple platforms.
287287
:::
288288

289-
#### `tabBarIconRenderingMode` <Badge text="iOS" type="info" />
289+
#### `tabBarIconRenderingMode`
290290

291291
Rendering mode for image icons.
292292

293293
- Type: `'automatic' | 'alwaysOriginal'`
294294
- Default: `'automatic'`
295295

296-
Use `alwaysOriginal` to preserve the original colors of multicolor image icons, such as logos or branded assets, instead of applying the native iOS tab tint.
296+
Use `alwaysOriginal` to preserve the original colors of multicolor image icons, such as logos or branded assets, instead of applying the native tab tint.
297297

298298
```tsx
299299
<Tab.Screen
@@ -308,7 +308,7 @@ Use `alwaysOriginal` to preserve the original colors of multicolor image icons,
308308

309309
:::warning
310310

311-
Metro transformers that modify the import resolutions of images to something that is *not* React Native's `ImageSource` will break this. A notable community example of such is [react-native-svg-transformer](https://github.com/kristerkari/react-native-svg-transformer).
311+
Metro transformers that modify the import resolutions of images to something that is _not_ React Native's `ImageSource` will break this. A notable community example of such is [react-native-svg-transformer](https://github.com/kristerkari/react-native-svg-transformer).
312312

313313
For best results, avoid the use of such transformers altogether.
314314

packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabView.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
44
import android.content.Context
55
import android.content.res.ColorStateList
66
import android.content.res.Configuration
7+
import android.graphics.PorterDuff
78
import android.graphics.drawable.ColorDrawable
89
import android.graphics.drawable.Drawable
910
import android.os.Build
@@ -19,6 +20,7 @@ import android.view.ViewGroup
1920
import android.widget.FrameLayout
2021
import android.widget.LinearLayout
2122
import android.widget.TextView
23+
import androidx.core.view.MenuItemCompat
2224
import androidx.core.view.forEachIndexed
2325
import coil3.ImageLoader
2426
import coil3.asDrawable
@@ -246,9 +248,11 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
246248
}
247249

248250
menuItem.isVisible = !item.hidden
251+
updateIconTintMode(menuItem, item)
249252
if (iconSources.containsKey(index)) {
250253
getDrawable(iconSources[index]!!) {
251254
menuItem.icon = it
255+
updateIconTintMode(menuItem, item)
252256
}
253257
}
254258

@@ -297,6 +301,13 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
297301
return bottomNavigation.menu.findItem(index) ?: bottomNavigation.menu.add(0, index, 0, title)
298302
}
299303

304+
private fun updateIconTintMode(menuItem: MenuItem, item: TabInfo) {
305+
MenuItemCompat.setIconTintMode(
306+
menuItem,
307+
if (item.iconRenderingMode == "alwaysOriginal") PorterDuff.Mode.DST else null
308+
)
309+
}
310+
300311
fun setIcons(icons: ReadableArray?) {
301312
if (icons == null || icons.size() == 0) {
302313
return
@@ -316,6 +327,9 @@ class ReactBottomNavigationView(context: Context) : LinearLayout(context) {
316327
bottomNavigation.menu.findItem(idx)?.let { menuItem ->
317328
getDrawable(imageSource) {
318329
menuItem.icon = it
330+
items.getOrNull(idx)?.let { item ->
331+
updateIconTintMode(menuItem, item)
332+
}
319333
}
320334
}
321335
}

packages/react-native-bottom-tabs/android/src/main/java/com/rcttabview/RCTTabViewManager.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ data class TabInfo(
2424
val badgeBackgroundColor: Int?,
2525
val badgeTextColor: Int?,
2626
val activeTintColor: Int?,
27+
val iconRenderingMode: String?,
2728
val hidden: Boolean,
2829
val testID: String?
2930
)
@@ -104,6 +105,7 @@ class RCTTabViewManager(context: ReactApplicationContext) :
104105
badgeBackgroundColor = if (item.hasKey("badgeBackgroundColor")) item.getInt("badgeBackgroundColor") else null,
105106
badgeTextColor = if (item.hasKey("badgeTextColor")) item.getInt("badgeTextColor") else null,
106107
activeTintColor = if (item.hasKey("activeTintColor")) item.getInt("activeTintColor") else null,
108+
iconRenderingMode = if (item.hasKey("iconRenderingMode")) item.getString("iconRenderingMode") else null,
107109
hidden = if (item.hasKey("hidden")) item.getBoolean("hidden") else false,
108110
testID = item.getString("testID")
109111
)

packages/react-native-bottom-tabs/src/TabView.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,9 @@ interface Props<Route extends BaseRoute> {
147147
}) => ImageSource | AppleIcon | undefined | null;
148148

149149
/**
150-
* Get the iOS rendering mode for the tab icon, uses `route.iconRenderingMode` by default.
150+
* Get the rendering mode for the tab icon, uses `route.iconRenderingMode` by default.
151151
*
152152
* Use `alwaysOriginal` to preserve multicolor image icons instead of applying the native tab tint.
153-
*
154-
* @platform ios
155153
*/
156154
getIconRenderingMode?: (props: {
157155
route: Route;

packages/react-navigation/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export type NativeBottomTabNavigationOptions = {
7272
tabBarIcon?: (props: { focused: boolean }) => ImageSourcePropType | AppleIcon;
7373

7474
/**
75-
* Rendering mode for the tab icon. Use `alwaysOriginal` on iOS to preserve multicolor image icons.
75+
* Rendering mode for the tab icon. Use `alwaysOriginal` to preserve multicolor image icons.
7676
*/
7777
tabBarIconRenderingMode?: IconRenderingMode;
7878

0 commit comments

Comments
 (0)