Skip to content

Commit

Permalink
Merge pull request #49 from dohooo/refactor/useOffsetX
Browse files Browse the repository at this point in the history
Refactor/use offset x
  • Loading branch information
dohooo authored Dec 5, 2021
2 parents 70ab9e5 + e9a3007 commit 48205b8
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 81 deletions.
69 changes: 46 additions & 23 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Animated, {
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated';
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';

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

Expand All @@ -26,21 +27,25 @@ const data: ImageSourcePropType[] = [

export default function App() {
const progressValue = useSharedValue<number>(0);
const r = React.useRef<ICarouselInstance | null>(null);
const defaultCarouselRef = React.useRef<ICarouselInstance | null>(null);
const parallaxCarouselRef = React.useRef<ICarouselInstance | null>(null);

return (
<View
style={{
flex: 1,
alignItems: 'center',
backgroundColor: 'black',
paddingTop: 100,
paddingTop: 50,
}}
>
<View style={{ height: 240 }}>
<View
style={{
height: 240,
}}
>
<Carousel<ImageSourcePropType>
defaultIndex={1}
ref={r}
ref={defaultCarouselRef}
width={window.width}
data={data}
parallaxScrollingScale={0.8}
Expand All @@ -67,13 +72,13 @@ export default function App() {
<Button
title="Prev"
onPress={() => {
r.current?.prev();
defaultCarouselRef.current?.prev();
}}
/>
<Button
title="Next"
onPress={() => {
r.current?.next();
defaultCarouselRef.current?.next();
}}
/>
</View>
Expand All @@ -85,6 +90,7 @@ export default function App() {
mode="parallax"
width={window.width}
data={data}
ref={parallaxCarouselRef}
parallaxScrollingScale={0.8}
renderItem={(source) => (
<View style={{ flex: 1 }}>
Expand Down Expand Up @@ -114,6 +120,12 @@ export default function App() {
index={index}
key={index}
length={data.length}
onPress={() => {
parallaxCarouselRef.current?.goToIndex(
index,
true
);
}}
/>
);
})}
Expand All @@ -128,8 +140,9 @@ const PaginationItem: React.FC<{
index: number;
length: number;
animValue: Animated.SharedValue<number>;
onPress?: () => void;
}> = (props) => {
const { animValue, index, length } = props;
const { onPress, animValue, index, length } = props;
const width = 20;

const animStyle = useAnimatedStyle(() => {
Expand All @@ -154,22 +167,32 @@ const PaginationItem: React.FC<{
],
};
}, [animValue, index, length]);

return (
<View
style={{
backgroundColor: 'white',
width,
height: width,
borderRadius: 50,
overflow: 'hidden',
}}
<TouchableWithoutFeedback
containerStyle={{ flex: 1 }}
onPress={onPress}
>
<Animated.View
style={[
{ borderRadius: 50, backgroundColor: 'tomato', flex: 1 },
animStyle,
]}
/>
</View>
<View
style={{
backgroundColor: 'white',
width,
height: width,
borderRadius: 50,
overflow: 'hidden',
}}
>
<Animated.View
style={[
{
borderRadius: 50,
backgroundColor: 'tomato',
flex: 1,
},
animStyle,
]}
/>
</View>
</TouchableWithoutFeedback>
);
};
14 changes: 6 additions & 8 deletions src/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { CarouselItem } from './CarouselItem';
import type { TMode } from './layouts';
import { ParallaxLayout } from './layouts/index';
import { useCarouselController } from './hooks/useCarouselController';
import { useComputedAnim } from './hooks/useComputedAnim';
import { useAutoPlay } from './hooks/useAutoPlay';
import { useIndexController } from './hooks/useIndexController';
import { usePropsErrorBoundary } from './hooks/usePropsErrorBoundary';
Expand Down Expand Up @@ -204,8 +203,6 @@ function Carousel<T extends unknown = any>(
return _data;
}, [_data, loop]);

const computedAnimResult = useComputedAnim(width, data.length);

const indexController = useIndexController({
originalLength: _data.length,
length: data.length,
Expand Down Expand Up @@ -247,13 +244,14 @@ function Carousel<T extends unknown = any>(
}, [sharedPreIndex, sharedIndex, computedIndex, props, run]);

const offsetX = useDerivedValue(() => {
const x = handlerOffsetX.value % computedAnimResult.TOTAL_WIDTH;
const totalWidth = width * data.length;
const x = handlerOffsetX.value % totalWidth;

if (!loop) {
return handlerOffsetX.value;
}
return isNaN(x) ? 0 : x;
}, [computedAnimResult, loop]);
}, [loop, width, data]);

useAnimatedReaction(
() => offsetX.value,
Expand Down Expand Up @@ -389,7 +387,7 @@ function Carousel<T extends unknown = any>(
<ParallaxLayout
parallaxScrollingOffset={parallaxScrollingOffset}
parallaxScrollingScale={parallaxScrollingScale}
computedAnimResult={computedAnimResult}
data={data}
width={width}
handlerOffsetX={offsetX}
index={i}
Expand All @@ -402,7 +400,7 @@ function Carousel<T extends unknown = any>(
default:
return (
<CarouselItem
computedAnimResult={computedAnimResult}
data={data}
width={width}
height={height}
handlerOffsetX={offsetX}
Expand All @@ -418,7 +416,7 @@ function Carousel<T extends unknown = any>(
[
loop,
mode,
computedAnimResult,
data,
height,
offsetX,
parallaxScrollingOffset,
Expand Down
9 changes: 5 additions & 4 deletions src/CarouselItem.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
import React from 'react';
import { FlexStyle, View } from 'react-native';
import Animated, { useAnimatedStyle } from 'react-native-reanimated';
import type { IComputedAnimResult } from './hooks/useComputedAnim';
import { useOffsetX } from './hooks/useOffsetX';

export const CarouselItem: React.FC<{
loop?: boolean;
index: number;
handlerOffsetX: Animated.SharedValue<number>;
width: number;
data: unknown[];
height?: FlexStyle['height'];
computedAnimResult: IComputedAnimResult;
}> = (props) => {
const {
handlerOffsetX,
index,
children,
width,
height = '100%',
computedAnimResult,
loop,
data,
} = props;

const x = useOffsetX({
handlerOffsetX,
index,
width,
computedAnimResult,
data,
loop,
});

const offsetXStyle = useAnimatedStyle(() => {
return {
transform: [{ translateX: x.value - index * width }],
Expand Down
23 changes: 0 additions & 23 deletions src/hooks/useComputedAnim.ts

This file was deleted.

78 changes: 59 additions & 19 deletions src/hooks/useOffsetX.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,73 @@ import Animated, {
interpolate,
useDerivedValue,
} from 'react-native-reanimated';
import type { IComputedAnimResult } from './useComputedAnim';

interface IOpts {
index: number;
width: number;
computedAnimResult: IComputedAnimResult;
handlerOffsetX: Animated.SharedValue<number>;
data: unknown[];
type?: 'positive' | 'negative';
viewCount?: number;
loop?: boolean;
}

export const useOffsetX = (opts: IOpts) => {
const { handlerOffsetX, index, width, computedAnimResult, loop } = opts;
const {
handlerOffsetX,
index,
width,
loop,
data,
type = 'positive',
viewCount = 1,
} = opts;
const ITEM_LENGTH = data.length;
const VALID_LENGTH = ITEM_LENGTH - 1;
const TOTAL_WIDTH = width * ITEM_LENGTH;
const HALF_WIDTH = 0.5 * width;

const x = useDerivedValue(() => {
const { MAX, MIN, TOTAL_WIDTH, HALF_WIDTH } = computedAnimResult;
const defaultPos = width * index;
if (loop) {
const defaultPos = width * index;
const startPos =
defaultPos > MAX
? MAX - defaultPos
: defaultPos < MIN
? MIN - defaultPos
: defaultPos;
function getDefaultPos(
_type: 'positive' | 'negative',
_count: number
): {
MAX: number;
MIN: number;
startPos: number;
} {
let MAX = null;
let MIN = null;

let startPos: number = defaultPos;

if (_type === 'positive') {
MAX = _count * width;
MIN = -(VALID_LENGTH - _count) * width;
} else {
MAX = (VALID_LENGTH - _count) * width;
MIN = -_count * width;
}

if (defaultPos > MAX) {
startPos = MAX - defaultPos;
}

return {
startPos,
MAX,
MIN,
};
}

const { startPos, MAX, MIN } = getDefaultPos(type, viewCount);

const inputRange = [
-TOTAL_WIDTH,
-(MAX + HALF_WIDTH) - startPos - 1,
-(MAX + HALF_WIDTH) - startPos,
MIN - HALF_WIDTH - startPos - 1,
MIN - HALF_WIDTH - startPos,
0,
MAX + HALF_WIDTH - startPos,
MAX + HALF_WIDTH - startPos + 1,
Expand All @@ -38,11 +78,11 @@ export const useOffsetX = (opts: IOpts) => {

const outputRange = [
startPos,
1.5 * width - 1,
-(MAX + HALF_WIDTH),
MAX + HALF_WIDTH - 1,
MIN - HALF_WIDTH,
startPos,
MAX + HALF_WIDTH,
-(1.5 * width - 1),
MIN - HALF_WIDTH + 1,
startPos,
];

Expand All @@ -54,8 +94,8 @@ export const useOffsetX = (opts: IOpts) => {
);
}

const startPos = width * index;
return handlerOffsetX.value + startPos;
}, [loop, computedAnimResult]);
return handlerOffsetX.value + defaultPos;
}, [loop, data, viewCount, type]);

return x;
};
Loading

0 comments on commit 48205b8

Please sign in to comment.