Skip to content

Commit

Permalink
feat: add stack layout
Browse files Browse the repository at this point in the history
  • Loading branch information
dohooo committed Dec 20, 2021
1 parent 6a4ffea commit 5a70a23
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 2 deletions.
3 changes: 3 additions & 0 deletions example/src/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const LayoutsPage: Array<Record<'name', keyof RootStackParamList>> = [
{
name: 'Parallax',
},
{
name: 'Stack',
},
{
name: 'Complex',
},
Expand Down
3 changes: 3 additions & 0 deletions example/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack';
import Home from './home';
import NormalComponent from './normal';
import ParallaxComponent from './parallax';
import StackComponent from './stack';
import ComplexComponent from './complex';
import SnapCarouselComplexComponent from './snap-carousel-complex';

Expand All @@ -14,6 +15,7 @@ export type RootStackParamList = {
Home: undefined;
Normal: undefined;
Parallax: undefined;
Stack: undefined;
Complex: undefined;
SnapCarouselComplex: undefined;
};
Expand All @@ -33,6 +35,7 @@ function App() {
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Normal" component={NormalComponent} />
<Stack.Screen name="Parallax" component={ParallaxComponent} />
<Stack.Screen name="Stack" component={StackComponent} />
<Stack.Screen name="Complex" component={ComplexComponent} />
<Stack.Screen
name="SnapCarouselComplex"
Expand Down
38 changes: 38 additions & 0 deletions example/src/stack/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as React from 'react';
import { Dimensions } from 'react-native';
import { View } from 'react-native-ui-lib';
import Carousel from '../../../src/index';
import { CAROUSEL_ITEMS } from '../contant';

const window = Dimensions.get('window');
const PAGE_WIDTH = window.width;

function Index() {
return (
<View
style={{
flex: 1,
}}
>
<Carousel
mode="stack"
width={PAGE_WIDTH}
height={PAGE_WIDTH / 2}
style={{ borderWidth: 1, borderColor: 'red' }}
data={CAROUSEL_ITEMS}
renderItem={(backgroundColor) => (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor,
}}
/>
)}
/>
</View>
);
}

export default Index;
18 changes: 17 additions & 1 deletion src/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Animated, {
useSharedValue,
} from 'react-native-reanimated';
import { CarouselItem } from './CarouselItem';
import { ParallaxLayout } from './layouts/index';
import { ParallaxLayout, StackLayout } from './layouts/index';
import { useCarouselController } from './hooks/useCarouselController';
import { useAutoPlay } from './hooks/useAutoPlay';
import { useIndexController } from './hooks/useIndexController';
Expand Down Expand Up @@ -206,6 +206,22 @@ function Carousel<T>(
{renderItem(item, i)}
</ParallaxLayout>
);
case 'stack':
return (
<StackLayout
data={data}
width={width}
height={height}
handlerOffsetX={offsetX}
index={i}
key={i}
loop={loop}
visibleRanges={visibleRanges}
vertical={vertical}
>
{renderItem(item, i)}
</StackLayout>
);
default:
return (
<CarouselItem
Expand Down
140 changes: 140 additions & 0 deletions src/layouts/StackLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import Animated, {
Extrapolate,
interpolate,
runOnJS,
useAnimatedReaction,
useAnimatedStyle,
} from 'react-native-reanimated';
import { useOffsetX } from '../hooks/useOffsetX';
import type { IVisibleRanges } from '../hooks/useVisibleRanges';
import { LazyView } from '../LazyView';

export const StackLayout: React.FC<{
loop?: boolean;
handlerOffsetX: Animated.SharedValue<number>;
index: number;
width: number;
height: number;
data: unknown[];
visibleRanges: IVisibleRanges;
vertical?: boolean;
}> = (props) => {
const {
handlerOffsetX,
index,
width,
height,
loop,
data,
children,
visibleRanges,
vertical,
} = props;

const [shouldUpdate, setShouldUpdate] = React.useState(false);

const size = React.useMemo(
() => (vertical ? height : width),
[vertical, width, height]
);

const x = useOffsetX(
{
handlerOffsetX,
index,
size,
data,
loop,
type: 'negative',
viewCount: 1,
},
visibleRanges
);

const offsetXStyle = useAnimatedStyle(() => {
const startPosition = (x.value - index * width) / width;

return {
left: interpolate(
startPosition,
[-(index + 1), -index, 0],
[-width, 0, 0],
Extrapolate.CLAMP
),
transform: [
{
scale: interpolate(
startPosition,
[-(index + 1), -index, 0, data.length - index],
[
0.7,
0.7,
0.7 - index * 0.1,
0.7 - (data.length - index) * 0.1,
]
),
},
{
rotateZ: `${interpolate(
startPosition,
[-(index + 1), -index, 0],
[-45, 0, 0]
)}deg`,
},
{
translateY: interpolate(
startPosition,
[-(index + 1), -index, 0, data.length - index],
[0, 0, index * 40, (data.length - index) * 40]
),
},
],
zIndex: -x.value,
};
}, [loop, vertical]);

const updateView = React.useCallback(
(negativeRange: number[], positiveRange: number[]) => {
setShouldUpdate(
(index >= negativeRange[0] && index <= negativeRange[1]) ||
(index >= positiveRange[0] && index <= positiveRange[1])
);
},
[index]
);

useAnimatedReaction(
() => visibleRanges.value,
() => {
runOnJS(updateView)(
visibleRanges.value.negativeRange,
visibleRanges.value.positiveRange
);
},
[visibleRanges.value]
);

return (
<Animated.View
style={[
{
width,
height,
position: 'absolute',
},
offsetXStyle,
styles.container,
]}
>
<LazyView shouldUpdate={shouldUpdate}>{children}</LazyView>
</Animated.View>
);
};

const styles = StyleSheet.create({
container: {
alignSelf: 'center',
},
});
3 changes: 2 additions & 1 deletion src/layouts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { ParallaxLayout } from './ParallaxLayout';
export { StackLayout } from './StackLayout';

export type TMode = 'default' | 'parallax';
export type TMode = 'default' | 'parallax' | 'stack';

0 comments on commit 5a70a23

Please sign in to comment.