From aa8ca13dc21c96973e386a91f5d94a66a0af3156 Mon Sep 17 00:00:00 2001 From: gongdao123 Date: Wed, 9 Nov 2022 11:56:31 +0800 Subject: [PATCH 1/3] fix the tab header not sync with swipe issue when header is long --- src/TabBar.tsx | 64 ++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/TabBar.tsx b/src/TabBar.tsx index 9025bd48..22924b1a 100644 --- a/src/TabBar.tsx +++ b/src/TabBar.tsx @@ -62,7 +62,6 @@ export type Props = SceneRendererProps & { contentContainerStyle?: StyleProp; style?: StyleProp; gap?: number; - testID?: string; }; type FlattenedTabWidth = string | number | undefined; @@ -121,7 +120,7 @@ const getTranslateX = ( I18nManager.isRTL ? 1 : -1 ); -const getTabBarWidth = ({ +const getTabBarWidth = ({ navigationState, layout, gap, @@ -150,7 +149,7 @@ const getTabBarWidth = ({ ); }; -const normalizeScrollValue = ({ +const normalizeScrollValue = ({ layout, navigationState, gap, @@ -183,7 +182,7 @@ const normalizeScrollValue = ({ return scrollValue; }; -const getScrollAmount = ({ +const getScrollAmount = ({ layout, navigationState, gap, @@ -238,8 +237,8 @@ const getAccessibilityLabelDefault = ({ route }: Scene) => typeof route.accessibilityLabel === 'string' ? route.accessibilityLabel : typeof route.title === 'string' - ? route.title - : undefined; + ? route.title + : undefined; const renderIndicatorDefault = (props: IndicatorProps) => ( @@ -247,7 +246,7 @@ const renderIndicatorDefault = (props: IndicatorProps) => ( const getTestIdDefault = ({ route }: Scene) => route.testID; -export default function TabBar({ +export default function TabBar ({ getLabelText = getLabelTextDefault, getAccessible = getAccessibleDefault, getAccessibilityLabel = getAccessibilityLabelDefault, @@ -275,7 +274,6 @@ export default function TabBar({ renderTabBarItem, style, tabStyle, - testID, }: Props) { const [layout, setLayout] = React.useState({ width: 0, height: 0 }); const [tabWidths, setTabWidths] = React.useState>({}); @@ -283,6 +281,7 @@ export default function TabBar({ const isFirst = React.useRef(true); const scrollAmount = useAnimatedValue(0); const measuredTabWidths = React.useRef>({}); + const measureTabWidthsTimer = React.useRef>(null); const { routes } = navigationState; const flattenedTabWidth = getFlattenedTabWidth(tabStyle); @@ -296,9 +295,10 @@ export default function TabBar({ flattenedTabWidth, }); + const mesureRoutes = routes.slice(0, navigationState.index + 1) const hasMeasuredTabWidths = Boolean(layout.width) && - routes.every((r) => typeof tabWidths[r.key] === 'number'); + mesureRoutes.every((r) => typeof tabWidths[r.key] === 'number'); React.useEffect(() => { if (isFirst.current) { @@ -371,18 +371,17 @@ export default function TabBar({ pressOpacity: pressOpacity, onLayout: isWidthDynamic ? (e: LayoutChangeEvent) => { - measuredTabWidths.current[route.key] = e.nativeEvent.layout.width; - - // When we have measured widths for all of the tabs, we should updates the state - // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app - if ( - routes.every( - (r) => typeof measuredTabWidths.current[r.key] === 'number' - ) - ) { - setTabWidths({ ...measuredTabWidths.current }); - } + measuredTabWidths.current[route.key] = e.nativeEvent.layout.width; + + // When we have measured widths for all of the tabs, we should updates the state + // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app + if (measureTabWidthsTimer.current) { + clearTimeout(measureTabWidthsTimer.current) } + measureTabWidthsTimer.current = setTimeout(() => { + setTabWidths({ ...measuredTabWidths.current }); + }, 300) + } : undefined, onPress: () => { const event: Scene & Event = { @@ -407,13 +406,13 @@ export default function TabBar({ // Calculate the deafult width for tab for FlatList to work defaultTabWidth: !isWidthDynamic ? getComputedTabWidth( - index, - layout, - routes, - scrollEnabled, - tabWidths, - getFlattenedTabWidth(tabStyle) - ) + index, + layout, + routes, + scrollEnabled, + tabWidths, + getFlattenedTabWidth(tabStyle) + ) : undefined, }; @@ -464,9 +463,9 @@ export default function TabBar({ styles.tabContent, scrollEnabled ? { - width: - tabBarWidth > separatorsWidth ? tabBarWidth : tabBarWidthPercent, - } + width: + tabBarWidth > separatorsWidth ? tabBarWidth : tabBarWidthPercent, + } : styles.container, contentContainerStyle, ], @@ -504,8 +503,8 @@ export default function TabBar({ tabBarWidth > separatorsWidth ? { width: tabBarWidth - separatorsWidth } : scrollEnabled - ? { width: tabBarWidthPercent } - : null, + ? { width: tabBarWidthPercent } + : null, indicatorContainerStyle, ]} > @@ -550,7 +549,6 @@ export default function TabBar({ renderItem={renderItem} onScroll={handleScroll} ref={flatListRef} - testID={testID} /> From 8d13fec66c1eafae88a9e9cff620b4614138278f Mon Sep 17 00:00:00 2001 From: gongdao123 Date: Wed, 9 Nov 2022 13:20:54 +0800 Subject: [PATCH 2/3] fix lint issue and add back testID --- src/TabBar.tsx | 63 ++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/TabBar.tsx b/src/TabBar.tsx index 22924b1a..4a3f9035 100644 --- a/src/TabBar.tsx +++ b/src/TabBar.tsx @@ -62,6 +62,7 @@ export type Props = SceneRendererProps & { contentContainerStyle?: StyleProp; style?: StyleProp; gap?: number; + testID?: string; }; type FlattenedTabWidth = string | number | undefined; @@ -120,7 +121,7 @@ const getTranslateX = ( I18nManager.isRTL ? 1 : -1 ); -const getTabBarWidth = ({ +const getTabBarWidth = ({ navigationState, layout, gap, @@ -149,7 +150,7 @@ const getTabBarWidth = ({ ); }; -const normalizeScrollValue = ({ +const normalizeScrollValue = ({ layout, navigationState, gap, @@ -182,7 +183,7 @@ const normalizeScrollValue = ({ return scrollValue; }; -const getScrollAmount = ({ +const getScrollAmount = ({ layout, navigationState, gap, @@ -237,8 +238,8 @@ const getAccessibilityLabelDefault = ({ route }: Scene) => typeof route.accessibilityLabel === 'string' ? route.accessibilityLabel : typeof route.title === 'string' - ? route.title - : undefined; + ? route.title + : undefined; const renderIndicatorDefault = (props: IndicatorProps) => ( @@ -246,7 +247,7 @@ const renderIndicatorDefault = (props: IndicatorProps) => ( const getTestIdDefault = ({ route }: Scene) => route.testID; -export default function TabBar ({ +export default function TabBar({ getLabelText = getLabelTextDefault, getAccessible = getAccessibleDefault, getAccessibilityLabel = getAccessibilityLabelDefault, @@ -281,7 +282,9 @@ export default function TabBar ({ const isFirst = React.useRef(true); const scrollAmount = useAnimatedValue(0); const measuredTabWidths = React.useRef>({}); - const measureTabWidthsTimer = React.useRef>(null); + const measureTabWidthsTimer = React.useRef>(null); const { routes } = navigationState; const flattenedTabWidth = getFlattenedTabWidth(tabStyle); @@ -295,7 +298,7 @@ export default function TabBar ({ flattenedTabWidth, }); - const mesureRoutes = routes.slice(0, navigationState.index + 1) + const mesureRoutes = routes.slice(0, navigationState.index + 1); const hasMeasuredTabWidths = Boolean(layout.width) && mesureRoutes.every((r) => typeof tabWidths[r.key] === 'number'); @@ -371,17 +374,17 @@ export default function TabBar ({ pressOpacity: pressOpacity, onLayout: isWidthDynamic ? (e: LayoutChangeEvent) => { - measuredTabWidths.current[route.key] = e.nativeEvent.layout.width; - - // When we have measured widths for all of the tabs, we should updates the state - // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app - if (measureTabWidthsTimer.current) { - clearTimeout(measureTabWidthsTimer.current) + measuredTabWidths.current[route.key] = e.nativeEvent.layout.width; + + // When we have measured widths for all of the tabs, we should updates the state + // We avoid doing separate setState for each layout since it triggers multiple renders and slows down app + if (measureTabWidthsTimer.current) { + clearTimeout(measureTabWidthsTimer.current); + } + measureTabWidthsTimer.current = setTimeout(() => { + setTabWidths({ ...measuredTabWidths.current }); + }, 300); } - measureTabWidthsTimer.current = setTimeout(() => { - setTabWidths({ ...measuredTabWidths.current }); - }, 300) - } : undefined, onPress: () => { const event: Scene & Event = { @@ -406,13 +409,13 @@ export default function TabBar ({ // Calculate the deafult width for tab for FlatList to work defaultTabWidth: !isWidthDynamic ? getComputedTabWidth( - index, - layout, - routes, - scrollEnabled, - tabWidths, - getFlattenedTabWidth(tabStyle) - ) + index, + layout, + routes, + scrollEnabled, + tabWidths, + getFlattenedTabWidth(tabStyle) + ) : undefined, }; @@ -463,9 +466,9 @@ export default function TabBar ({ styles.tabContent, scrollEnabled ? { - width: - tabBarWidth > separatorsWidth ? tabBarWidth : tabBarWidthPercent, - } + width: + tabBarWidth > separatorsWidth ? tabBarWidth : tabBarWidthPercent, + } : styles.container, contentContainerStyle, ], @@ -503,8 +506,8 @@ export default function TabBar ({ tabBarWidth > separatorsWidth ? { width: tabBarWidth - separatorsWidth } : scrollEnabled - ? { width: tabBarWidthPercent } - : null, + ? { width: tabBarWidthPercent } + : null, indicatorContainerStyle, ]} > From da1b970b158c65c7809bdeb6116ce815050fa37c Mon Sep 17 00:00:00 2001 From: gongdao123 Date: Wed, 9 Nov 2022 13:27:04 +0800 Subject: [PATCH 3/3] add back remaining testID --- src/TabBar.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/TabBar.tsx b/src/TabBar.tsx index 4a3f9035..7ba5af89 100644 --- a/src/TabBar.tsx +++ b/src/TabBar.tsx @@ -275,6 +275,7 @@ export default function TabBar({ renderTabBarItem, style, tabStyle, + testID, }: Props) { const [layout, setLayout] = React.useState({ width: 0, height: 0 }); const [tabWidths, setTabWidths] = React.useState>({}); @@ -552,6 +553,7 @@ export default function TabBar({ renderItem={renderItem} onScroll={handleScroll} ref={flatListRef} + testID={testID} />