diff --git a/docs/docs/docs/guides/usage-with-react-navigation.md b/docs/docs/docs/guides/usage-with-react-navigation.md index 747c2a3..25e9622 100644 --- a/docs/docs/docs/guides/usage-with-react-navigation.md +++ b/docs/docs/docs/guides/usage-with-react-navigation.md @@ -55,6 +55,16 @@ Whether to show labels in tabs. Defaults to true. Whether to disable page animations between tabs. (iOS only) +#### `scrollEdgeAppearance` + +Describes the appearance attributes for the tabBar to use when an observable scroll view is scrolled to the bottom. (iOS only) + +Available options: +- `default` - uses default background and shadow values. +- `transparent` - uses transparent background and no shadow. +- `opaque` - uses set of opaque colors that are appropriate for the current theme + +Note: It's recommended to use `transparent` or `opaque` without lazy loading as the tab bar background flashes when a view is rendered lazily. #### `sidebarAdaptable` A tab bar style that adapts to each platform. (Apple platforms only) diff --git a/example/src/App.tsx b/example/src/App.tsx index 599b6a7..07ffa0f 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -31,6 +31,10 @@ const FourTabsNoAnimations = () => { return ; }; +const FourTabsTransparentScrollEdgeAppearance = () => { + return ; +}; + const examples = [ { component: ThreeTabs, name: 'Three Tabs' }, { component: FourTabs, name: 'Four Tabs' }, @@ -42,6 +46,10 @@ const examples = [ screenOptions: { headerShown: false }, }, { component: FourTabsNoAnimations, name: 'Four Tabs - no animations' }, + { + component: FourTabsTransparentScrollEdgeAppearance, + name: 'Four Tabs - Transparent scroll edge appearance', + }, { component: NativeBottomTabs, name: 'Native Bottom Tabs' }, { component: JSBottomTabs, name: 'JS Bottom Tabs' }, { diff --git a/example/src/Examples/FourTabs.tsx b/example/src/Examples/FourTabs.tsx index 45ab147..344cbde 100644 --- a/example/src/Examples/FourTabs.tsx +++ b/example/src/Examples/FourTabs.tsx @@ -8,11 +8,13 @@ import { Chat } from '../Screens/Chat'; interface Props { ignoresTopSafeArea?: boolean; disablePageAnimations?: boolean; + scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent'; } export default function FourTabs({ ignoresTopSafeArea = false, disablePageAnimations = false, + scrollEdgeAppearance = 'default', }: Props) { const [index, setIndex] = useState(0); const [routes] = useState([ @@ -53,6 +55,7 @@ export default function FourTabs({ ignoresTopSafeArea={ignoresTopSafeArea} sidebarAdaptable disablePageAnimations={disablePageAnimations} + scrollEdgeAppearance={scrollEdgeAppearance} navigationState={{ index, routes }} onIndexChange={setIndex} renderScene={renderScene} diff --git a/ios/RCTTabViewViewManager.mm b/ios/RCTTabViewViewManager.mm index 0127534..e60c896 100644 --- a/ios/RCTTabViewViewManager.mm +++ b/ios/RCTTabViewViewManager.mm @@ -31,5 +31,6 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(labeled, BOOL) RCT_EXPORT_VIEW_PROPERTY(ignoresTopSafeArea, BOOL) RCT_EXPORT_VIEW_PROPERTY(disablePageAnimations, BOOL) +RCT_EXPORT_VIEW_PROPERTY(scrollEdgeAppearance, NSString) @end diff --git a/ios/TabViewImpl.swift b/ios/TabViewImpl.swift index f35670d..f0502a4 100644 --- a/ios/TabViewImpl.swift +++ b/ios/TabViewImpl.swift @@ -14,6 +14,7 @@ class TabViewProps: ObservableObject { @Published var labeled: Bool? @Published var ignoresTopSafeArea: Bool? @Published var disablePageAnimations: Bool = false + @Published var scrollEdgeAppearance: String? } /** @@ -70,16 +71,29 @@ struct TabViewImpl: View { } onSelect(newValue) } - .onAppear { + .onChange(of: props.scrollEdgeAppearance) { newValue in if #available(iOS 15.0, *) { - // This causes issues with lazy loading making the TabView background blink. - let appearance = UITabBarAppearance() - UITabBar.appearance().scrollEdgeAppearance = appearance + UITabBar.appearance().scrollEdgeAppearance = configureAppearance(for: newValue ?? "") } } } } +private func configureAppearance(for appearanceType: String) -> UITabBarAppearance { + let appearance = UITabBarAppearance() + + switch appearanceType { + case "opaque": + appearance.configureWithOpaqueBackground() + case "transparent": + appearance.configureWithTransparentBackground() + default: + appearance.configureWithDefaultBackground() + } + + return appearance +} + struct TabItem: View { var title: String? var icon: UIImage? diff --git a/ios/TabViewProvider.swift b/ios/TabViewProvider.swift index 428df86..ead7613 100644 --- a/ios/TabViewProvider.swift +++ b/ios/TabViewProvider.swift @@ -59,6 +59,12 @@ struct TabData: Codable { } } + @objc var scrollEdgeAppearance: NSString? { + didSet { + props.scrollEdgeAppearance = scrollEdgeAppearance as? String + } + } + @objc var items: NSArray? { didSet { props.items = parseTabData(from: items) diff --git a/src/TabView.tsx b/src/TabView.tsx index 99dbc2f..6c30e50 100644 --- a/src/TabView.tsx +++ b/src/TabView.tsx @@ -36,6 +36,10 @@ interface Props { * Whether to disable page animations between tabs. (iOS only) */ disablePageAnimations?: boolean; + /** + * Describes the appearance attributes for the tabBar to use when an observable scroll view is scrolled to the bottom. (iOS only) + */ + scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent'; /** * State for the tab view. * diff --git a/src/TabViewNativeComponent.ts b/src/TabViewNativeComponent.ts index 358575c..e15681b 100644 --- a/src/TabViewNativeComponent.ts +++ b/src/TabViewNativeComponent.ts @@ -22,6 +22,7 @@ export interface TabViewProps extends ViewProps { icons?: ReadonlyArray; labeled?: boolean; sidebarAdaptable?: boolean; + scrollEdgeAppearance?: string; } export default codegenNativeComponent('RCTTabView');