A React Native component that supports a collapsible header and custom refresh control, powered by Reanimated v2 and GestureHandler V2.
showtime-profile.mp4
This is a React Native tab view component that wraps gestures and animations on top of react-native-tab-view. The source code can be found here. You can see this context on Twitter.
- Collapsible header.
- Support for FlashList. *(see this)
- Custom refresh control.
- Bounce effect support on iOS.
- Support for iOS, Android, and Web.
- Zoom header when pulling to refresh. *(see this thread)
Before installing this package, you should first follow the installation instructions for:
FlashList is not a required dependency, but for optimal performance, it is recommended to use FlashList instead of the standard FlatList implementation
And then, you can install the package using the following command:
yarn add @showtime-xyz/tab-view
- Basic Example
- Zoom Effect with Pull-To-Refresh
- Showtime Profile Example
- ...more to come!
The API for this package is similar to react-native-tab-view, with extended props. A basic usage example is shown below:
import React, { useCallback, useState } from "react";
import { StatusBar, Text, View } from "react-native";
import { useSharedValue } from "react-native-reanimated";
import { Route, TabView } from "@showtime-xyz/tab-view";
import { TabFlashList } from "./tab-flash-list";
const StatusBarHeight = StatusBar.currentHeight ?? 0;
const TabScene = ({ route }: any) => {
return (
<TabFlashList
index={route.index}
data={new Array(20).fill(0)}
estimatedItemSize={60}
renderItem={({ index }) => {
return (
<View
style={{
height: 60,
backgroundColor: "#fff",
marginBottom: 8,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>{`${route.title}-Item-${index}`}</Text>
</View>
);
}}
/>
);
};
export function Example() {
const [isRefreshing, setIsRefreshing] = useState(false);
const [routes] = useState<Route[]>([
{ key: "like", title: "Like", index: 0 },
{ key: "owner", title: "Owner", index: 1 },
{ key: "created", title: "Created", index: 2 },
]);
const [index, setIndex] = useState(0);
const animationHeaderPosition = useSharedValue(0);
const animationHeaderHeight = useSharedValue(0);
const renderScene = useCallback(({ route }: any) => {
switch (route.key) {
case "like":
return <TabScene route={route} index={0} />;
case "owner":
return <TabScene route={route} index={1} />;
case "created":
return <TabScene route={route} index={2} />;
default:
return null;
}
}, []);
const onStartRefresh = async () => {
setIsRefreshing(true);
setTimeout(() => {
console.log("onStartRefresh");
setIsRefreshing(false);
}, 300);
};
const renderHeader = () => (
<View style={{ height: 300, backgroundColor: "#000" }}></View>
);
return (
<TabView
onStartRefresh={onStartRefresh}
isRefreshing={isRefreshing}
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
lazy
renderScrollHeader={renderHeader}
minHeaderHeight={44 + StatusBarHeight}
animationHeaderPosition={animationHeaderPosition}
animationHeaderHeight={animationHeaderHeight}
/>
);
}
... API documentation will be available soon. 🔜
To learn how to contribute to this repository and understand the development workflow, please refer to the contributing guide.
Special thanks to @Daavidaviid for experimenting with the zoom header effect with pull-to-refresh.
MIT
Made with create-react-native-library