Skip to content

Commit 09e8ac6

Browse files
feat(navigation): implemented indicator responsible to scroll changes
1 parent a701866 commit 09e8ac6

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

src/navigation/tabs/primary-tabs/PrimaryTabs.component.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import React, {useCallback, useEffect, useState} from 'react';
22
import {View, type ViewProps, type DimensionValue, type StyleProp, type ViewStyle, type TextStyle, type LayoutChangeEvent} from 'react-native';
3-
import Animated, {useSharedValue, type WithSpringConfig, Extrapolation, withSpring, useAnimatedStyle, interpolate} from 'react-native-reanimated';
3+
import Animated, {
4+
withSpring,
5+
interpolate,
6+
Extrapolation,
7+
useSharedValue,
8+
useAnimatedStyle,
9+
type SharedValue,
10+
type WithSpringConfig,
11+
} from 'react-native-reanimated';
412

513
import {type Tab} from '../tab.type';
614
import {styles} from './primary-tabs.styles';
@@ -14,6 +22,7 @@ export interface PrimaryTabsProps<T, Y> extends ViewProps {
1422
activeTab: T;
1523

1624
animConfig?: WithSpringConfig;
25+
scrollAnim?: SharedValue<number>;
1726

1827
tabIconProps?: Y;
1928
title?: string;
@@ -24,8 +33,6 @@ export interface PrimaryTabsProps<T, Y> extends ViewProps {
2433
indicatorStyle?: StyleProp<ViewStyle>;
2534
tabsContainerStyle?: StyleProp<ViewStyle>;
2635
tabInnerContentStyle?: StyleProp<ViewStyle>;
27-
28-
onTabPress: (routeName: T) => void;
2936
}
3037

3138
const BASE_INDICATOR_WIDTH = 33;
@@ -35,6 +42,7 @@ export const PrimaryTabs = <T extends string, Y extends IconProps>({
3542
activeTab,
3643

3744
badgeSize,
45+
scrollAnim,
3846
animConfig = {} as WithSpringConfig,
3947

4048
tabStyle,
@@ -44,8 +52,6 @@ export const PrimaryTabs = <T extends string, Y extends IconProps>({
4452
indicatorStyle,
4553
tabsContainerStyle,
4654
tabInnerContentStyle,
47-
48-
onTabPress,
4955
...props
5056
}: PrimaryTabsProps<T, Y>) => {
5157
const [tabTextWidths, setTabTextWidths] = useState<number[]>(tabs.map(() => 0));
@@ -94,7 +100,12 @@ export const PrimaryTabs = <T extends string, Y extends IconProps>({
94100
const maxPosition = calcStartIndicatorPosition(tabs.length, tabs.length - 1);
95101

96102
return {
97-
start: `${interpolate(indicatorStartPos.value, [0, maxPosition], [0, maxPosition * 100], Extrapolation.CLAMP)}%`,
103+
start: `${interpolate(
104+
scrollAnim ? scrollAnim.value : indicatorStartPos.value,
105+
[0, maxPosition],
106+
[0, maxPosition * 100],
107+
Extrapolation.CLAMP
108+
)}%`,
98109
};
99110
}, [tabs]);
100111

@@ -116,7 +127,6 @@ export const PrimaryTabs = <T extends string, Y extends IconProps>({
116127
key={tab.routeName}
117128
onInnerContentLayout={handleTextLayout(index)}
118129
{...tab}
119-
onPress={onTabPress}
120130
active={tab.routeName === activeTab}
121131
iconProps={tabIconProps}
122132
badgeSize={badgeSize}

src/navigation/tabs/secondary-tabs/SecondaryTabs.component.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import React, {useCallback, useEffect} from 'react';
22
import {View, type ViewProps, type StyleProp, type ViewStyle, type TextStyle} from 'react-native';
3-
import Animated, {useSharedValue, type WithSpringConfig, Extrapolation, withSpring, useAnimatedStyle, interpolate} from 'react-native-reanimated';
3+
import Animated, {
4+
withSpring,
5+
interpolate,
6+
Extrapolation,
7+
useSharedValue,
8+
useAnimatedStyle,
9+
type SharedValue,
10+
type WithSpringConfig,
11+
} from 'react-native-reanimated';
412

513
import {type Tab} from '../tab.type';
614
import {styles} from './secondary-tabs.styles';
@@ -15,6 +23,7 @@ export interface SecondaryTabsProps<T, Y> extends ViewProps {
1523

1624
badgeSize?: BadgeSize;
1725
animConfig?: WithSpringConfig;
26+
scrollAnim?: SharedValue<number>;
1827

1928
tabIconProps?: Y;
2029
tabStyle?: StyleProp<ViewStyle>;
@@ -23,15 +32,14 @@ export interface SecondaryTabsProps<T, Y> extends ViewProps {
2332
indicatorStyle?: StyleProp<ViewStyle>;
2433
tabsContainerStyle?: StyleProp<ViewStyle>;
2534
tabInnerContentStyle?: StyleProp<ViewStyle>;
26-
27-
onTabPress: (routeName: T) => void;
2835
}
2936

3037
export const SecondaryTabs = <T extends string, Y extends IconProps>({
3138
tabs,
3239
activeTab,
3340

3441
badgeSize,
42+
scrollAnim,
3543
animConfig = {} as WithSpringConfig,
3644

3745
tabStyle,
@@ -42,8 +50,6 @@ export const SecondaryTabs = <T extends string, Y extends IconProps>({
4250
tabsContainerStyle,
4351
tabInnerContentStyle,
4452

45-
onTabPress,
46-
4753
...props
4854
}: SecondaryTabsProps<T, Y>) => {
4955
const {primary, outlineVariant} = useTheme();
@@ -70,14 +76,20 @@ export const SecondaryTabs = <T extends string, Y extends IconProps>({
7076
const indicatorAnimatedStyle = useAnimatedStyle(() => {
7177
const maxPosition = calcStartIndicatorPosition(tabs.length, tabs.length - 1);
7278

73-
return {start: `${interpolate(indicatorStartPos.value, [0, maxPosition], [0, maxPosition * 100], Extrapolation.CLAMP)}%`};
79+
return {
80+
start: `${interpolate(
81+
scrollAnim ? scrollAnim.value : indicatorStartPos.value,
82+
[0, maxPosition],
83+
[0, maxPosition * 100],
84+
Extrapolation.CLAMP
85+
)}%`,
86+
};
7487
}, [tabs]);
7588

7689
const renderSecondaryTab = (tab: Tab<T, Y>) => (
7790
<TabComponent
7891
key={tab.routeName}
7992
{...tab}
80-
onPress={onTabPress}
8193
type={TabType.SECONDARY}
8294
active={tab.routeName === activeTab}
8395
iconProps={tabIconProps}

src/navigation/tabs/tab.type.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ export interface Tab<T, Y> extends Omit<TouchableOpacityProps, 'onPress'> {
88
badge?: string;
99
iconProps?: Y;
1010
titleStyle?: StyleProp<TextStyle>;
11+
12+
onPress: (routeName: T) => void;
1113
}

0 commit comments

Comments
 (0)