Skip to content

Commit

Permalink
feat: add snapToInterval
Browse files Browse the repository at this point in the history
  • Loading branch information
r0b0t3d committed Apr 20, 2021
1 parent da0e0c4 commit 51a34e0
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 17 deletions.
10 changes: 6 additions & 4 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

import React from 'react';
import { StyleSheet, View, Image } from 'react-native';
import { StyleSheet, View, Image, Dimensions } from 'react-native';
import Carousel from '@r0b0t3d/react-native-carousel';

const data = [
Expand Down Expand Up @@ -58,16 +58,18 @@ const data = [
},
];

const { width } = Dimensions.get('window');

export default function App() {
return (
<View style={styles.container}>
<Carousel
style={{ height: 200 }}
data={data}
loop
autoPlay
loop={false}
autoPlay={false}
duration={3000}
animation="parallax"
itemWidth={width - 50}
renderImage={(item) => {
return (
<Image
Expand Down
42 changes: 33 additions & 9 deletions src/components/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import React, {
Ref,
useMemo,
} from 'react';
import { View, Dimensions, StyleSheet } from 'react-native';
import { View, Dimensions, StyleSheet, Platform } from 'react-native';
import { useInterval } from '@r0b0t3d/react-native-hooks';
import Animated, {
useSharedValue,
Expand All @@ -32,6 +32,8 @@ function Carousel(
useIndicator = true,
animation,
sliderWidth = wWidth,
itemWidth = wWidth,
firstItemAlignment = 'center',
indicatorContainerStyle,
renderIndicator,
renderImage,
Expand Down Expand Up @@ -64,9 +66,8 @@ function Carousel(

const refreshPage = useCallback(
(e) => {
const viewSize = e.layoutMeasurement;
// Divide the horizontal offset by the width of the view to see which page is visible
const page = e.contentOffset.x / viewSize.width;
const page = e.contentOffset.x / itemWidth;
const leftPage = Math.round(page);
const rightPage = leftPage + 1;
const diff = 0.2;
Expand All @@ -76,6 +77,7 @@ function Carousel(
} else if (rightPage - page <= diff) {
pageNum = rightPage;
}
console.log('refreshPage', pageNum, currentPage);
if (pageNum !== currentPage) {
if (expectedPosition.current === pageNum) {
freeze.value = false;
Expand All @@ -100,6 +102,8 @@ function Carousel(

const handleScrollTo = useCallback(
(page: number, animated = true) => {
console.log('handleScrollTo', page);

const to = page * sliderWidth;
if (getRef()) {
getRef().scrollTo({ x: to, y: 0, animated });
Expand All @@ -109,10 +113,12 @@ function Carousel(
);

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

const jumpTo = useCallback(
Expand Down Expand Up @@ -199,18 +205,36 @@ function Carousel(
style={styles.container}
horizontal
showsHorizontalScrollIndicator={false}
pagingEnabled
scrollEventThrottle={16}
snapToInterval={itemWidth}
snapToAlignment={'center'}
decelerationRate="fast"
scrollEventThrottle={16}
onScroll={scrollHandler}
bounces={false}
// iOS ONLY
contentInset={
firstItemAlignment === 'center'
? {
top: 0,
left: (sliderWidth - itemWidth) / 2, // Left spacing for the very first card
bottom: 0,
right: (sliderWidth - itemWidth) / 2, // Right spacing for the very last card
}
: {}
}
contentContainerStyle={{
// contentInset alternative for Android
paddingHorizontal:
Platform.OS === 'android' ? (sliderWidth - itemWidth) / 2 : 0, // Horizontal spacing before and after the ScrollView
}}
{...{ scrollViewProps }}
>
{pageItems.map((item, i) => (
<PageItem
key={`${item.id}-${i}`}
item={item}
index={i}
itemWidth={itemWidth}
animatedValue={animatedScroll}
animation={animation}
renderImage={renderImage}
Expand Down
8 changes: 4 additions & 4 deletions src/components/PageItem.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React from 'react';
import { Dimensions, Image, StyleSheet, View } from 'react-native';
import { Image, StyleSheet, View } from 'react-native';
import type Animated from 'react-native-reanimated';
import { withParallax } from '../animators/parrallax';
import type { CarouselData } from '../types';

const { width: wWidth } = Dimensions.get('window');

type Props = {
item: CarouselData;
index: number;
Expand All @@ -14,6 +12,7 @@ type Props = {
animatedValue: Animated.SharedValue<number>;
animation?: 'parallax';
freeze: Animated.SharedValue<boolean>;
itemWidth: number;
};

export default function PageItem({
Expand All @@ -24,6 +23,7 @@ export default function PageItem({
animatedValue,
animation,
freeze,
itemWidth,
}: Props) {
function renderContent() {
if (renderImage) {
Expand Down Expand Up @@ -57,7 +57,7 @@ export default function PageItem({
<View
collapsable={false}
style={{
width: wWidth,
width: itemWidth,
overflow: 'hidden',
backgroundColor: 'black',
}}
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export type CarouselProps = {
indicatorContainerStyle?: StyleProp<ViewStyle>;
animation?: 'parallax';
sliderWidth?: number;
itemWidth?: number;
firstItemAlignment?: 'start' | 'center'
renderIndicator?: (props: {
selected: boolean;
index: number;
Expand Down

0 comments on commit 51a34e0

Please sign in to comment.