Skip to content
This repository was archived by the owner on Nov 27, 2022. It is now read-only.

Commit d03d49d

Browse files
committed
feat: add animateOnIndexChange to enable/disable animation
1 parent 20b5062 commit d03d49d

File tree

7 files changed

+136
-22
lines changed

7 files changed

+136
-22
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ You can also pass a boolean to enable lazy for all of the scenes:
280280

281281
```js
282282
<TabView
283-
lazy
283+
lazy
284284
/>
285285
```
286286

@@ -316,6 +316,10 @@ Callback which is called when the swipe gesture starts, i.e. the user touches th
316316

317317
Callback which is called when the swipe gesture ends, i.e. the user lifts their finger from the screen after the swipe gesture.
318318

319+
##### `animateOnIndexChange`
320+
321+
Function which determines whether the animation is executed on index change
322+
319323
##### `initialLayout`
320324

321325
Object containing the initial height and width of the screens. Passing this will improve the initial rendering performance. For most apps, this is a good default:

example/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import CustomIndicatorExample from './CustomIndicatorExample';
2222
import CustomTabBarExample from './CustomTabBarExample';
2323
import CoverflowExample from './CoverflowExample';
2424
import TabBarGapExample from './TabBarGapExample';
25+
import CustomAnimationExample from './CustomAnimationExample';
2526

2627
type ExampleComponentType = React.ComponentType<{}> & {
2728
title: string;
@@ -43,6 +44,7 @@ const EXAMPLE_COMPONENTS: ExampleComponentType[] = [
4344
CustomTabBarExample,
4445
CoverflowExample,
4546
TabBarGapExample,
47+
CustomAnimationExample,
4648
];
4749

4850
const ExampleList = () => {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import * as React from 'react';
2+
import { StyleSheet } from 'react-native';
3+
import {
4+
TabView,
5+
TabBar,
6+
SceneMap,
7+
NavigationState,
8+
SceneRendererProps,
9+
} from 'react-native-tab-view';
10+
import Article from './Shared/Article';
11+
import Albums from './Shared/Albums';
12+
import Chat from './Shared/Chat';
13+
import Contacts from './Shared/Contacts';
14+
15+
type State = NavigationState<{
16+
key: string;
17+
title: string;
18+
}>;
19+
20+
const animateOnIndexChange = (currentIndex: number, nextIndex: number) => {
21+
return Math.abs(currentIndex - nextIndex) === 1;
22+
};
23+
24+
const CustomAnimationExample = () => {
25+
const [index, onIndexChange] = React.useState(1);
26+
const [routes] = React.useState([
27+
{ key: 'article', title: 'Article' },
28+
{ key: 'contacts', title: 'Contacts' },
29+
{ key: 'albums', title: 'Albums' },
30+
{ key: 'chat', title: 'Chat' },
31+
]);
32+
33+
const renderTabBar = (
34+
props: SceneRendererProps & { navigationState: State }
35+
) => (
36+
<TabBar
37+
{...props}
38+
scrollEnabled
39+
indicatorStyle={styles.indicator}
40+
style={styles.tabbar}
41+
tabStyle={styles.tab}
42+
labelStyle={styles.label}
43+
/>
44+
);
45+
46+
const renderScene = SceneMap({
47+
albums: Albums,
48+
contacts: Contacts,
49+
article: Article,
50+
chat: Chat,
51+
});
52+
53+
return (
54+
<TabView
55+
lazy
56+
navigationState={{
57+
index,
58+
routes,
59+
}}
60+
renderScene={renderScene}
61+
renderTabBar={renderTabBar}
62+
onIndexChange={onIndexChange}
63+
animateOnIndexChange={animateOnIndexChange}
64+
/>
65+
);
66+
};
67+
68+
CustomAnimationExample.title = 'Custom Animation';
69+
CustomAnimationExample.backgroundColor = '#3f51b5';
70+
CustomAnimationExample.appbarElevation = 0;
71+
72+
export default CustomAnimationExample;
73+
74+
const styles = StyleSheet.create({
75+
tabbar: {
76+
backgroundColor: '#3f51b5',
77+
},
78+
tab: {
79+
width: 'auto',
80+
},
81+
indicator: {
82+
backgroundColor: '#ffeb3b',
83+
},
84+
label: {
85+
fontWeight: '400',
86+
},
87+
});

src/PagerViewAdapter.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default function PagerViewAdapter<T extends Route>({
4040
onSwipeStart,
4141
onSwipeEnd,
4242
children,
43+
animateOnIndexChange,
4344
style,
4445
...rest
4546
}: Props<T>) {
@@ -58,13 +59,22 @@ export default function PagerViewAdapter<T extends Route>({
5859
navigationStateRef.current = navigationState;
5960
});
6061

61-
const jumpTo = React.useCallback((key: string) => {
62-
const index = navigationStateRef.current.routes.findIndex(
63-
(route: { key: string }) => route.key === key
64-
);
65-
66-
pagerRef.current?.setPage(index);
67-
}, []);
62+
const jumpTo = React.useCallback(
63+
(key: string) => {
64+
const index = navigationStateRef.current.routes.findIndex(
65+
(route: { key: string }) => route.key === key
66+
);
67+
if (
68+
animateOnIndexChange &&
69+
!animateOnIndexChange(indexRef.current, index)
70+
) {
71+
pagerRef.current?.setPageWithoutAnimation(index);
72+
} else {
73+
pagerRef.current?.setPage(index);
74+
}
75+
},
76+
[animateOnIndexChange]
77+
);
6878

6979
React.useEffect(() => {
7080
if (keyboardDismissMode === 'auto') {

src/PanResponderAdapter.tsx

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export default function PanResponderAdapter<T extends Route>({
5757
onSwipeStart,
5858
onSwipeEnd,
5959
children,
60+
animateOnIndexChange,
6061
style,
6162
}: Props<T>) {
6263
const { routes, index } = navigationState;
@@ -80,23 +81,30 @@ export default function PanResponderAdapter<T extends Route>({
8081
const offset = -index * layoutRef.current.width;
8182

8283
const { timing, ...transitionConfig } = DefaultTransitionSpec;
83-
84-
Animated.parallel([
85-
timing(panX, {
86-
...transitionConfig,
87-
toValue: offset,
88-
useNativeDriver: false,
89-
}),
90-
]).start(({ finished }) => {
91-
if (finished) {
92-
onIndexChangeRef.current(index);
93-
pendingIndexRef.current = undefined;
94-
}
95-
});
84+
if (
85+
animateOnIndexChange &&
86+
!animateOnIndexChange(currentIndexRef.current, index)
87+
) {
88+
onIndexChangeRef.current(index);
89+
pendingIndexRef.current = undefined;
90+
} else {
91+
Animated.parallel([
92+
timing(panX, {
93+
...transitionConfig,
94+
toValue: offset,
95+
useNativeDriver: false,
96+
}),
97+
]).start(({ finished }) => {
98+
if (finished) {
99+
onIndexChangeRef.current(index);
100+
pendingIndexRef.current = undefined;
101+
}
102+
});
103+
}
96104

97105
pendingIndexRef.current = index;
98106
},
99-
[panX]
107+
[animateOnIndexChange, panX]
100108
);
101109

102110
React.useEffect(() => {

src/TabView.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export default function TabView<T extends Route>({
5151
style,
5252
swipeEnabled = true,
5353
tabBarPosition = 'top',
54+
animateOnIndexChange,
5455
}: Props<T>) {
5556
const [layout, setLayout] = React.useState({
5657
width: 0,
@@ -87,6 +88,7 @@ export default function TabView<T extends Route>({
8788
onSwipeEnd={onSwipeEnd}
8889
onIndexChange={jumpToIndex}
8990
style={pagerStyle}
91+
animateOnIndexChange={animateOnIndexChange}
9092
>
9193
{({ position, render, addEnterListener, jumpTo }) => {
9294
// All of the props here must not change between re-renders

src/types.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@ export type PagerProps = Omit<
5555
swipeEnabled?: boolean;
5656
onSwipeStart?: () => void;
5757
onSwipeEnd?: () => void;
58+
animateOnIndexChange?: (currentIndex: number, nextIndex: number) => boolean;
5859
};

0 commit comments

Comments
 (0)