Skip to content

Commit

Permalink
feat: use scrollTo method from reanimated
Browse files Browse the repository at this point in the history
  • Loading branch information
r0b0t3d committed Oct 17, 2021
1 parent 763f445 commit 4346480
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 31 deletions.
15 changes: 8 additions & 7 deletions src/components/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Animated, {
useSharedValue,
useAnimatedScrollHandler,
runOnJS,
useAnimatedRef,
} from 'react-native-reanimated';
import type { CarouselProps } from '../types';
import PageItem from './PageItem';
Expand Down Expand Up @@ -44,9 +45,9 @@ function Carousel<TData>({
}: CarouselProps<TData>) {
const currentPage = useSharedValue(0);
const animatedScroll = useSharedValue(currentPage.value * sliderWidth);
const freeze = useSharedValue(loop);
const freeze = useSharedValue(false);
const [isDragging, setDragging] = useState(false);
const expectedPosition = useRef(-1);
const expectedPosition = useSharedValue(-1);
const pageMapper = useRef<Record<number, number>>({});
const { currentPage: animatedPage, totalPage } = useCarouselContext();

Expand All @@ -55,7 +56,7 @@ function Carousel<TData>({
return firstItemAlignment === 'center' || loop ? padding : spaceHeadTail;
}, [sliderWidth, itemWidth, firstItemAlignment, loop, spaceHeadTail]);

const scrollViewRef = useRef<any>(null);
const scrollViewRef = useAnimatedRef<any>();

const offsets = useMemo(() => {
return generateOffsets({
Expand Down Expand Up @@ -114,7 +115,7 @@ function Carousel<TData>({

const jumpTo = useCallback(
(page: number, delay = 200) => {
expectedPosition.current = page;
expectedPosition.value = page;
if (Platform.OS === 'android') {
freeze.value = true;
}
Expand Down Expand Up @@ -187,12 +188,12 @@ function Carousel<TData>({
const refreshPage = useCallback(
(offset) => {
'worklet';
const pageNum = findNearestPage(offset, offsets, 20);
const pageNum = findNearestPage(offset, offsets, 20);
if (pageNum === -1) {
return;
}
if (pageNum !== currentPage.value) {
if (expectedPosition.current === pageNum) {
if (expectedPosition.value === pageNum) {
freeze.value = false;
}
currentPage.value = pageNum;
Expand Down Expand Up @@ -304,7 +305,7 @@ function Carousel<TData>({
}

return (
<View style={[style]}>
<View style={style}>
<Animated.ScrollView
ref={scrollViewRef}
{...scrollViewProps}
Expand Down
45 changes: 28 additions & 17 deletions src/components/PageItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Image, StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
import Animated, {
interpolate,
useAnimatedStyle,
useDerivedValue,
} from 'react-native-reanimated';
import type { CarouselProps } from '../types';

Expand Down Expand Up @@ -34,42 +35,52 @@ export default function PageItem<TData = any>({
inactiveScale,
containerStyle,
}: Props<TData>) {
// @ts-ignore
const animatedStyle = useAnimatedStyle(() => {
const scale = useDerivedValue(() => {
const inputRange = [offset - itemWidth, offset, offset + itemWidth];
const scaleOutputRange = [inactiveScale, 1, inactiveScale];
return interpolate(animatedValue.value, inputRange, scaleOutputRange);
}, []);

const translateX = useDerivedValue(() => {
const inputRange = [offset - itemWidth, offset, offset + itemWidth];
const scaleOutputRange = freeze.value
? [1, 1, 1]
: [inactiveScale, 1, inactiveScale];
const opacityOutputRange = freeze.value
? [1, 1, 1]
: [inactiveOpacity, 1, inactiveOpacity];
const parallaxOutputRange = freeze.value
? [0, 0, 0]
: [-itemWidth / 2, 0, itemWidth / 4];

return interpolate(animatedValue.value, inputRange, parallaxOutputRange);
}, []);

const opacity = useDerivedValue(() => {
const inputRange = [offset - itemWidth, offset, offset + itemWidth];
const opacityOutputRange = freeze.value
? [1, 1, 1]
: [inactiveOpacity, 1, inactiveOpacity];
return interpolate(animatedValue.value, inputRange, opacityOutputRange);
}, []);
// @ts-ignore
const animatedStyle = useAnimatedStyle(() => {
const transform: ViewStyle['transform'] = [
{
scale: interpolate(animatedValue.value, inputRange, scaleOutputRange),
scale: scale.value,
},
];
if (animation === 'parallax') {
transform.push({
translateX: interpolate(
animatedValue.value,
inputRange,
parallaxOutputRange
),
translateX: translateX.value,
});
}
return {
opacity: interpolate(animatedValue.value, inputRange, opacityOutputRange),
opacity: opacity.value,
transform,
};
}, [inactiveScale, inactiveOpacity, animation, itemWidth, offset]);
}, []);

function renderContent() {
if (renderItem) {
return renderItem({ item, index }, { scrollPosition: animatedValue, offset });
return renderItem(
{ item, index },
{ scrollPosition: animatedValue, offset }
);
}
if (typeof item === 'object' && (item as any).source) {
return (
Expand Down
15 changes: 8 additions & 7 deletions src/components/PaginationIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import React, { useMemo } from 'react';
import { View, StyleSheet, ViewStyle } from 'react-native';
import { View, StyleSheet, ViewStyle, StyleProp } from 'react-native';
import Animated, {
useAnimatedStyle,
useDerivedValue,
Expand Down Expand Up @@ -113,10 +113,10 @@ function IndicatorItem({
currentPage: Animated.SharedValue<number>;
pageNumber: number;
configs: IndicatorConfigs;
activeIndicatorStyle?: ViewStyle;
indicatorStyle?: ViewStyle;
activeIndicatorStyle?: StyleProp<ViewStyle>;
indicatorStyle?: StyleProp<ViewStyle>;
}) {
const dotContainerStyle: ViewStyle = StyleSheet.flatten([
const dotContainerStyle: StyleProp<ViewStyle> = useMemo(()=> [
styles.dotContainer,
{
width: configs.indicatorSelectedWidth,
Expand All @@ -128,16 +128,17 @@ function IndicatorItem({
// Disable backgroundColor in activeIndicatorStyle
backgroundColor: undefined,
},
]);
const dotStyle: ViewStyle = StyleSheet.flatten([
], [activeIndicatorStyle]);

const dotStyle: StyleProp<ViewStyle> = useMemo(() => [
{
width: configs.indicatorWidth,
height: configs.indicatorWidth,
borderRadius: configs.indicatorWidth! / 2,
backgroundColor: configs.indicatorColor,
},
indicatorStyle,
]);
], [indicatorStyle]);

const animatedWidth = useDerivedValue(() => {
return withSpring(
Expand Down

0 comments on commit 4346480

Please sign in to comment.