Skip to content

Commit 9f0f34b

Browse files
authored
feat(iOS): scroll edge appearance (#54)
1 parent 95782ac commit 9f0f34b

File tree

8 files changed

+51
-4
lines changed

8 files changed

+51
-4
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ Whether to show labels in tabs. Defaults to true.
5555

5656
Whether to disable page animations between tabs. (iOS only)
5757

58+
#### `scrollEdgeAppearance`
59+
60+
Describes the appearance attributes for the tabBar to use when an observable scroll view is scrolled to the bottom. (iOS only)
61+
62+
Available options:
63+
- `default` - uses default background and shadow values.
64+
- `transparent` - uses transparent background and no shadow.
65+
- `opaque` - uses set of opaque colors that are appropriate for the current theme
66+
67+
Note: It's recommended to use `transparent` or `opaque` without lazy loading as the tab bar background flashes when a view is rendered lazily.
5868
#### `sidebarAdaptable`
5969

6070
A tab bar style that adapts to each platform. (Apple platforms only)

example/src/App.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ const FourTabsNoAnimations = () => {
3131
return <FourTabs disablePageAnimations />;
3232
};
3333

34+
const FourTabsTransparentScrollEdgeAppearance = () => {
35+
return <FourTabs scrollEdgeAppearance="transparent" />;
36+
};
37+
3438
const examples = [
3539
{ component: ThreeTabs, name: 'Three Tabs' },
3640
{ component: FourTabs, name: 'Four Tabs' },
@@ -42,6 +46,10 @@ const examples = [
4246
screenOptions: { headerShown: false },
4347
},
4448
{ component: FourTabsNoAnimations, name: 'Four Tabs - no animations' },
49+
{
50+
component: FourTabsTransparentScrollEdgeAppearance,
51+
name: 'Four Tabs - Transparent scroll edge appearance',
52+
},
4553
{ component: NativeBottomTabs, name: 'Native Bottom Tabs' },
4654
{ component: JSBottomTabs, name: 'JS Bottom Tabs' },
4755
{

example/src/Examples/FourTabs.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ import { Chat } from '../Screens/Chat';
88
interface Props {
99
ignoresTopSafeArea?: boolean;
1010
disablePageAnimations?: boolean;
11+
scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent';
1112
}
1213

1314
export default function FourTabs({
1415
ignoresTopSafeArea = false,
1516
disablePageAnimations = false,
17+
scrollEdgeAppearance = 'default',
1618
}: Props) {
1719
const [index, setIndex] = useState(0);
1820
const [routes] = useState([
@@ -53,6 +55,7 @@ export default function FourTabs({
5355
ignoresTopSafeArea={ignoresTopSafeArea}
5456
sidebarAdaptable
5557
disablePageAnimations={disablePageAnimations}
58+
scrollEdgeAppearance={scrollEdgeAppearance}
5659
navigationState={{ index, routes }}
5760
onIndexChange={setIndex}
5861
renderScene={renderScene}

ios/RCTTabViewViewManager.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ - (UIView *)view
3131
RCT_EXPORT_VIEW_PROPERTY(labeled, BOOL)
3232
RCT_EXPORT_VIEW_PROPERTY(ignoresTopSafeArea, BOOL)
3333
RCT_EXPORT_VIEW_PROPERTY(disablePageAnimations, BOOL)
34+
RCT_EXPORT_VIEW_PROPERTY(scrollEdgeAppearance, NSString)
3435

3536
@end

ios/TabViewImpl.swift

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class TabViewProps: ObservableObject {
1414
@Published var labeled: Bool?
1515
@Published var ignoresTopSafeArea: Bool?
1616
@Published var disablePageAnimations: Bool = false
17+
@Published var scrollEdgeAppearance: String?
1718
}
1819

1920
/**
@@ -70,16 +71,29 @@ struct TabViewImpl: View {
7071
}
7172
onSelect(newValue)
7273
}
73-
.onAppear {
74+
.onChange(of: props.scrollEdgeAppearance) { newValue in
7475
if #available(iOS 15.0, *) {
75-
// This causes issues with lazy loading making the TabView background blink.
76-
let appearance = UITabBarAppearance()
77-
UITabBar.appearance().scrollEdgeAppearance = appearance
76+
UITabBar.appearance().scrollEdgeAppearance = configureAppearance(for: newValue ?? "")
7877
}
7978
}
8079
}
8180
}
8281

82+
private func configureAppearance(for appearanceType: String) -> UITabBarAppearance {
83+
let appearance = UITabBarAppearance()
84+
85+
switch appearanceType {
86+
case "opaque":
87+
appearance.configureWithOpaqueBackground()
88+
case "transparent":
89+
appearance.configureWithTransparentBackground()
90+
default:
91+
appearance.configureWithDefaultBackground()
92+
}
93+
94+
return appearance
95+
}
96+
8397
struct TabItem: View {
8498
var title: String?
8599
var icon: UIImage?

ios/TabViewProvider.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ struct TabData: Codable {
5959
}
6060
}
6161

62+
@objc var scrollEdgeAppearance: NSString? {
63+
didSet {
64+
props.scrollEdgeAppearance = scrollEdgeAppearance as? String
65+
}
66+
}
67+
6268
@objc var items: NSArray? {
6369
didSet {
6470
props.items = parseTabData(from: items)

src/TabView.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ interface Props<Route extends BaseRoute> {
3636
* Whether to disable page animations between tabs. (iOS only)
3737
*/
3838
disablePageAnimations?: boolean;
39+
/**
40+
* Describes the appearance attributes for the tabBar to use when an observable scroll view is scrolled to the bottom. (iOS only)
41+
*/
42+
scrollEdgeAppearance?: 'default' | 'opaque' | 'transparent';
3943
/**
4044
* State for the tab view.
4145
*

src/TabViewNativeComponent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface TabViewProps extends ViewProps {
2222
icons?: ReadonlyArray<ImageSource>;
2323
labeled?: boolean;
2424
sidebarAdaptable?: boolean;
25+
scrollEdgeAppearance?: string;
2526
}
2627

2728
export default codegenNativeComponent<TabViewProps>('RCTTabView');

0 commit comments

Comments
 (0)