Skip to content

Commit

Permalink
feat: add additionalPagesPerSide
Browse files Browse the repository at this point in the history
  • Loading branch information
r0b0t3d committed Apr 27, 2021
1 parent d239bd3 commit f6c7ceb
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 66 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ function MyCarousel() {
| ----- | ----------- |:-------:|
| data | array of item to be rendered.<br>- `id: string`: this will be used as key to render<br>- `source: ImageSourcePropType`: optional. Image source. If you don't want to pass `source` here. You could use `renderItem` below to render your custom image.|
|loop?| Whether your carousel can loop or not | false |
|additionalPagesPerSide?| When looping, how many page will be added at head and tail to perform loop effect | 2 |
|autoPlay?| Auto animate to next image with `duration`.| false|
|duration?| duration to animate. used with `autoPlay` above|1000|
|animation?| predefined animation. Will be `parallax` for now||
Expand Down
5 changes: 3 additions & 2 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const data = [
'https://4.bp.blogspot.com/_N44PgSKJwQY/TOtoPtIo3_I/AAAAAAAAANE/7WwIFzgm-IU/s1600/Danboard.obstacles.jpg',
},
{
id: 'image5',
id: 'image4',
source: {
uri:
'https://i.pinimg.com/originals/97/17/8a/97178ac9a3e25b3080a0e7f8b728ac29.jpg',
Expand All @@ -49,7 +49,7 @@ const data = [
'https://i.pinimg.com/originals/97/17/8a/97178ac9a3e25b3080a0e7f8b728ac29.jpg',
},
{
id: 'image6',
id: 'image5',
source: {
uri:
'https://c4.wallpaperflare.com/wallpaper/289/627/693/danbo-cardboard-robot-hat-walk-wallpaper-preview.jpg',
Expand Down Expand Up @@ -79,6 +79,7 @@ export default function App() {
spaceBetween={50}
spaceHeadTail={20}
animatedPage={currentPage}
additionalPagesPerSide={3}
renderItem={(item) => {
return (
<Image
Expand Down
136 changes: 72 additions & 64 deletions src/components/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function Carousel(
style,
data,
loop = false,
additionalPagesPerSide = 2,
autoPlay = false,
duration = 1000,
animation,
Expand All @@ -40,25 +41,20 @@ function Carousel(
spaceHeadTail = 0,
renderItem,
onPageChange,
animatedPage = useSharedValue(0)
animatedPage = useSharedValue(0),
}: CarouselProps,
ref: Ref<CarouselRef>
) {
const currentPage = useSharedValue(loop ? 1 : 0);
const currentPage = useSharedValue(loop ? additionalPagesPerSide : 0);
const [isDragging, setDragging] = useState(false);
const animatedScroll = useSharedValue(currentPage.value * sliderWidth);
const freeze = useSharedValue(loop);
const expectedPosition = useRef(-1);
const horizontalPadding = useMemo(() => {
const padding = (sliderWidth - itemWidth) / 2
const padding = (sliderWidth - itemWidth) / 2;
return firstItemAlignment === 'center' || loop ? padding : spaceHeadTail;
}, [
sliderWidth,
itemWidth,
firstItemAlignment,
loop,
spaceHeadTail
]);
}, [sliderWidth, itemWidth, firstItemAlignment, loop, spaceHeadTail]);
const pageMapper = useRef<any>({})

const scrollViewRef = useRef<any>(null);

Expand All @@ -71,60 +67,37 @@ function Carousel(
return generateOffsets({
sliderWidth,
itemWidth,
itemCount: data.length + (loop ? 2 : 0),
itemCount: data.length + (loop ? additionalPagesPerSide * 2 : 0),
horizontalPadding,
});
}, [sliderWidth, itemWidth, data, horizontalPadding]);

const pageItems = useMemo(() => {
const items = [
...(loop ? [data[data.length - 1]] : []),
...data,
...(loop ? [data[0]] : []),
];
return items;
}, [data, loop]);

const getActualPage = useCallback((page: number) => {
if (loop) {
if (page > data.length) return 0;
if (page === 0) return data.length - 1;
return page - 1;
}
return page;
}, [loop, data]);

const handlePageChange = useCallback((page: number) => {
const actualPage = getActualPage(page);
animatedPage.value = actualPage;
if (onPageChange) {
onPageChange(actualPage);
}
currentPage.value = page;
if (!loop) return;
if (page === data.length + 1) {
jumpTo(1);
} else if (page === 0) {
jumpTo(data.length);
}
}, [onPageChange, loop])

const refreshPage = useCallback(
(offset) => {
'worklet';
const pageNum = findNearestPage(offset, offsets, 20);
if (pageNum === -1) {
return;
const headItems = data.slice(
data.length - additionalPagesPerSide,
data.length
);
const tailItems = data.slice(0, additionalPagesPerSide);
const newItems = [...headItems, ...data, ...tailItems];
for (let i = 0; i < newItems.length; i++) {
pageMapper.current[i] = (data.length - additionalPagesPerSide + i) % data.length;
}
if (pageNum !== currentPage.value) {
if (expectedPosition.current === pageNum) {
freeze.value = false;
}
runOnJS(handlePageChange)(pageNum);
return newItems;
} else {
for (let i = 0; i < data.length; i++) {
pageMapper.current[i] = i;
}
return data;
}
}, [data, loop]);

const getActualPage = useCallback(
(page: number) => {
return pageMapper.current[page]
},
[isDragging, offsets, handlePageChange]
);
[]
);

const getRef = useCallback(() => {
if (!scrollViewRef.current) return;
Expand All @@ -143,15 +116,6 @@ function Carousel(
[getRef, offsets]
);

useEffect(() => {
if (currentPage.value !== 0) {
setTimeout(() => {
handleScrollTo(currentPage.value, false);
freeze.value = false;
});
}
}, []);

const jumpTo = useCallback(
(page: number, delay = 200) => {
expectedPosition.current = page;
Expand All @@ -176,13 +140,57 @@ function Carousel(
handleScrollTo(prev);
}, [handleScrollTo]);

const handlePageChange = useCallback(
(page: number) => {
const actualPage = getActualPage(page);
animatedPage.value = actualPage;
if (onPageChange) {
onPageChange(actualPage);
}
currentPage.value = page;
if (!loop) return;
if (page === pageItems.length - 1) {
jumpTo((additionalPagesPerSide * 2) - 1);
} else if (page === 0) {
jumpTo(pageItems.length - (additionalPagesPerSide * 2));
}
},
[onPageChange, loop, getActualPage, jumpTo, pageItems]
);

const refreshPage = useCallback(
(offset) => {
'worklet';
const pageNum = findNearestPage(offset, offsets, 20);
if (pageNum === -1) {
return;
}
if (pageNum !== currentPage.value) {
if (expectedPosition.current === pageNum) {
freeze.value = false;
}
runOnJS(handlePageChange)(pageNum);
}
},
[isDragging, offsets, handlePageChange]
);

useInterval(
() => {
goNext();
},
!autoPlay || !loop || isDragging ? -1 : duration
);

useEffect(() => {
if (currentPage.value !== 0) {
setTimeout(() => {
handleScrollTo(currentPage.value, false);
freeze.value = false;
});
}
}, []);

const beginDrag = useCallback(() => {
setDragging(true);
}, []);
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type CarouselProps = {
style?: StyleProp<ViewStyle>;
data: CarouselData[];
loop?: boolean;
additionalPagesPerSide?: number;
autoPlay?: boolean;
duration?: number;
animation?: 'parallax';
Expand Down

0 comments on commit f6c7ceb

Please sign in to comment.