Skip to content

Commit 1358e8f

Browse files
committed
feat: 在NestedTabView组件中接入TabBarProps和PageViewProps
1 parent 9cbfede commit 1358e8f

File tree

5 files changed

+252
-93
lines changed

5 files changed

+252
-93
lines changed

example/src/pages/NestedTabViewExample.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ const HeadTabViewExample: React.FC<TabViewExampleProps> = (props) => {
99

1010
return (
1111
<NestedTabView
12+
style={{ flex: 1 }}
1213
stickyHeight={55} //TabBar的高度
1314
renderHeader={() => (
1415
<View style={{ backgroundColor: 'lightblue', height: 200 }}>
1516
<Text>Header</Text>
1617
</View>
1718
)}
19+
tabs={['tab1', 'tab2', '第三个tabs']}
20+
initialIndex={1}
21+
tabBarflex={'equal-width'}
1822
>
1923
<Nested.ScrollView>
2024
{new Array(80).fill(0).map((item, index) => {
@@ -35,6 +39,15 @@ const HeadTabViewExample: React.FC<TabViewExampleProps> = (props) => {
3539
);
3640
}}
3741
/>
42+
<Nested.ScrollView>
43+
{new Array(80).fill(0).map((item, index) => {
44+
return (
45+
<Text key={index} style={{ margin: 10, fontSize: 20 }}>
46+
{'ScrollView' + index}
47+
</Text>
48+
);
49+
})}
50+
</Nested.ScrollView>
3851
</NestedTabView>
3952
);
4053
};

src/components/NestedTabView/NestedScene.tsx

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import React, { useEffect, useRef } from 'react';
22
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
33
import {
4-
SharedValue,
5-
AnimatedRef,
64
useAnimatedRef,
75
useSharedValue,
86
useDerivedValue,
@@ -12,17 +10,7 @@ import {
1210
} from 'react-native-reanimated';
1311
import { scrollTo } from './util';
1412
import { useNested } from './hooks';
15-
16-
interface NestedSceneProps {
17-
registerNativeRef?: (ref: React.RefObject<any>) => void;
18-
registerChildInfo?: (
19-
index: number,
20-
scrollValue: SharedValue<number>,
21-
scrollRef: AnimatedRef<any>
22-
) => void;
23-
index?: number;
24-
ScrollableComponent: any;
25-
}
13+
import { NestedSceneProps } from './type';
2614

2715
const NestedScene: React.FC<NestedSceneProps> = (props) => {
2816
const {

src/components/NestedTabView/NestedTabView.tsx

Lines changed: 72 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,27 @@ import Animated, {
1010
cancelAnimation,
1111
useDerivedValue,
1212
} from 'react-native-reanimated';
13-
import {
14-
Gesture,
15-
GestureDetector,
16-
GestureHandlerRootView,
17-
} from 'react-native-gesture-handler';
13+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
1814
import { TabBar, TabBarRef } from '../TabBar';
19-
import { PageView, PageViewRef } from '../PageView';
20-
import { NestedContext, useNestRegister } from './hooks';
15+
import { PageStateType, PageView, PageViewRef } from '../PageView';
16+
import { NestedContext, useNestRegister, useVerifyProps } from './hooks';
2117
import { scrollTo } from './util';
22-
23-
const TABS = ['tab1', 'tab2'];
24-
25-
interface NestedTabViewProps {
26-
renderHeader: () => React.ReactNode;
27-
stickyHeight: number;
28-
children: React.ReactNode;
29-
}
18+
import { NestedTabViewProps } from './type';
3019

3120
const NestedTabView: React.FC<NestedTabViewProps> = (props) => {
32-
const { renderHeader, stickyHeight, children } = props;
21+
const {
22+
renderHeader,
23+
stickyHeight = 0,
24+
children,
25+
initialIndex = 0,
26+
style,
27+
tabProps,
28+
pageProps,
29+
onTabPress,
30+
onPageSelected,
31+
onPageScroll,
32+
onPageScrollStateChanged,
33+
} = useVerifyProps(props);
3334
const pageRef = useRef<PageViewRef>(null);
3435
const tabRef = useRef<TabBarRef>(null);
3536

@@ -45,7 +46,7 @@ const NestedTabView: React.FC<NestedTabViewProps> = (props) => {
4546
const integralYOffset = useSharedValue(0);
4647
const totalRef = useRef();
4748

48-
const currentIdx = useSharedValue(0);
49+
const currentIdx = useSharedValue(initialIndex);
4950

5051
// 所有scroll共享的滚动距离,用于控制Header以及顶吸
5152
const sharedTranslate = useSharedValue(0);
@@ -183,62 +184,61 @@ const NestedTabView: React.FC<NestedTabViewProps> = (props) => {
183184
});
184185

185186
return (
186-
<GestureHandlerRootView style={{ flex: 1 }}>
187-
<NestedContext.Provider
188-
value={{
189-
sharedTranslate,
190-
currentIdx,
191-
headerHeight,
192-
stickyHeight,
193-
}}
194-
>
195-
<GestureDetector gesture={panGesture}>
196-
<Animated.View style={[{ flex: 1 }, containerStyle]}>
197-
<PageView
198-
ref={pageRef}
199-
style={{ flex: 1 }}
200-
onPageSelected={(currentPage) => {
201-
tabRef.current &&
202-
tabRef.current?.keepScrollViewMiddle(currentPage);
203-
// onPageSelected && onPageSelected(currentPage)
204-
currentIdx.value = currentPage;
205-
}}
206-
onPageScroll={(translate) => {
207-
tabRef.current && tabRef.current?.syncCurrentIndex(translate);
208-
// onPageScroll && onPgeScroll(translate);
209-
}}
210-
onPageScrollStateChanged={() => {}}
187+
<NestedContext.Provider
188+
value={{
189+
sharedTranslate,
190+
currentIdx,
191+
headerHeight,
192+
stickyHeight,
193+
}}
194+
>
195+
<GestureDetector gesture={panGesture}>
196+
<Animated.View style={[style, containerStyle]}>
197+
<PageView
198+
{...{ ...pageProps }}
199+
ref={pageRef}
200+
onPageSelected={(currentPage) => {
201+
tabRef.current &&
202+
tabRef.current?.keepScrollViewMiddle(currentPage);
203+
onPageSelected && onPageSelected(currentPage);
204+
currentIdx.value = currentPage;
205+
}}
206+
onPageScroll={(translate) => {
207+
tabRef.current && tabRef.current?.syncCurrentIndex(translate);
208+
onPageScroll && onPageScroll(translate);
209+
}}
210+
onPageScrollStateChanged={(state: PageStateType) => {
211+
onPageScrollStateChanged && onPageScrollStateChanged(state);
212+
}}
213+
>
214+
{React.Children.map(children, (child: any, index) => {
215+
const injectProps = {
216+
registerNativeRef,
217+
registerChildInfo,
218+
index,
219+
};
220+
return React.cloneElement(child, injectProps);
221+
})}
222+
</PageView>
223+
<GestureDetector gesture={headerPan}>
224+
<Animated.View
225+
onLayout={handleHeaderLayout}
226+
style={[styles.headerContainer, headerStyle]}
211227
>
212-
{React.Children.map(children, (child: any, index) => {
213-
const injectProps = {
214-
registerNativeRef,
215-
registerChildInfo,
216-
index,
217-
};
218-
return React.cloneElement(child, injectProps);
219-
})}
220-
</PageView>
221-
<GestureDetector gesture={headerPan}>
222-
<Animated.View
223-
onLayout={handleHeaderLayout}
224-
style={[styles.headerContainer, headerStyle]}
225-
>
226-
{renderHeader && renderHeader()}
227-
<TabBar
228-
ref={tabRef}
229-
tabs={TABS}
230-
tabBarflex={'equal-width'}
231-
onTabPress={(index) => {
232-
pageRef.current && pageRef.current?.setPage(index);
233-
// onTabPress && onTabPress(index);
234-
}}
235-
/>
236-
</Animated.View>
237-
</GestureDetector>
238-
</Animated.View>
239-
</GestureDetector>
240-
</NestedContext.Provider>
241-
</GestureHandlerRootView>
228+
{renderHeader && renderHeader()}
229+
<TabBar
230+
{...{ ...tabProps }}
231+
ref={tabRef}
232+
onTabPress={(index) => {
233+
pageRef.current && pageRef.current?.setPage(index);
234+
onTabPress && onTabPress(index);
235+
}}
236+
/>
237+
</Animated.View>
238+
</GestureDetector>
239+
</Animated.View>
240+
</GestureDetector>
241+
</NestedContext.Provider>
242242
);
243243
};
244244

src/components/NestedTabView/hooks.ts

Lines changed: 112 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import {
1+
import React, {
22
useState,
33
useMemo,
44
useCallback,
55
createContext,
66
useContext,
77
} from 'react';
8+
import { Dimensions } from 'react-native';
89
import { SharedValue, AnimatedRef } from 'react-native-reanimated';
10+
import {
11+
NestedContextProps,
12+
NestedTabViewProps,
13+
NestedTabViewVerifyProps,
14+
} from './type';
915

1016
interface ChildInfoType {
1117
scrollValue: SharedValue<number>;
@@ -69,14 +75,112 @@ export const useNestRegister = () => {
6975
};
7076
};
7177

72-
interface NestedContextProps {
73-
sharedTranslate: SharedValue<number>;
74-
currentIdx: SharedValue<number>;
75-
headerHeight: number;
76-
stickyHeight: number;
77-
}
78-
7978
export const NestedContext = createContext<NestedContextProps>(
8079
{} as NestedContextProps
8180
);
8281
export const useNested = () => useContext(NestedContext);
82+
83+
const { width } = Dimensions.get('window');
84+
85+
export const useVerifyProps = (
86+
props: NestedTabViewProps
87+
): NestedTabViewVerifyProps => {
88+
const {
89+
tabs,
90+
tabBarflex,
91+
tabScrollEnabled,
92+
spacing,
93+
showSeparator,
94+
separatorComponent,
95+
hideSlider,
96+
sliderComponent,
97+
defaultSliderStyle,
98+
tabBarItemStyle,
99+
tabBarItemTitleStyle,
100+
activeTextColor,
101+
inactiveTextColor,
102+
tabStyle,
103+
104+
pageScrollEnabled,
105+
bounces,
106+
gestureBack,
107+
pageStyle,
108+
109+
onTabPress,
110+
onPageScroll,
111+
onPageScrollStateChanged,
112+
onPageSelected,
113+
114+
initialIndex,
115+
style,
116+
renderHeader,
117+
stickyHeight,
118+
children,
119+
} = props;
120+
121+
if (!Array.isArray(tabs)) {
122+
throw new Error('TabBar tabs must be array');
123+
}
124+
if (tabs.length <= 0) {
125+
throw new Error("TabBar tabs can't be empty");
126+
}
127+
128+
const pageSize = React.Children.count(children);
129+
if (pageSize === 0) {
130+
throw new Error('PageView must be contains at least one chid');
131+
}
132+
133+
if (pageSize !== tabs.length) {
134+
throw new Error('TabView tabs length must be equal children');
135+
}
136+
137+
let contentSize: number = width;
138+
if (style && style.width) {
139+
if (typeof style.width === 'number') {
140+
contentSize = style.width;
141+
} else {
142+
throw new Error('TabView width only support number');
143+
}
144+
}
145+
146+
const tabProps = {
147+
tabs,
148+
tabBarflex,
149+
tabScrollEnabled,
150+
spacing,
151+
showSeparator,
152+
separatorComponent,
153+
hideSlider,
154+
sliderComponent,
155+
defaultSliderStyle,
156+
tabBarItemStyle,
157+
tabBarItemTitleStyle,
158+
activeTextColor,
159+
inactiveTextColor,
160+
style: { width: contentSize, ...tabStyle },
161+
initialTab: initialIndex,
162+
};
163+
164+
const pageProps = {
165+
pageScrollEnabled,
166+
bounces,
167+
gestureBack,
168+
style: { flex: 1, width: contentSize, ...pageStyle },
169+
initialPage: initialIndex,
170+
};
171+
172+
return {
173+
pageProps,
174+
tabProps,
175+
style,
176+
children,
177+
renderHeader,
178+
stickyHeight,
179+
initialIndex,
180+
181+
onTabPress,
182+
onPageScroll,
183+
onPageScrollStateChanged,
184+
onPageSelected,
185+
};
186+
};

0 commit comments

Comments
 (0)