Skip to content

Commit 2a39346

Browse files
committed
feat: add new props to control or get information for carousel animation
re #285
1 parent f222427 commit 2a39346

File tree

11 files changed

+73
-61
lines changed

11 files changed

+73
-61
lines changed

docs/about.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ This is how it works in code.
2121
2222
1. First we need a unit `size` to help us calculate the scroll distance. When horizontal, `size` is equal to the `width` prop setting, when vertical, `size` is equal to the `height` prop setting.
2323

24-
2. Then we need a value `handlerOffsetX`, which is the current scroll distance, and it's a total value, if we scroll two, `handlerOffsetX` is equal to `size` * 2, if we scroll ten, `handlerOffsetX` is equal to `size` * 10.
24+
2. Then we need a value `handlerOffset`, which is the current scroll distance, and it's a total value, if we scroll two, `handlerOffset` is equal to `size` * 2, if we scroll ten, `handlerOffset` is equal to `size` * 10.
2525

2626
3. Followed by dealing with how to get at the end of the element at the right time to move to the front, this part of logic in `./src/hooks/useOffsetX.ts`. First we need to know the current window size (the total number of elements rendered on one side). The window size defaults to half the total number of elements, i.e. full render.
2727
![steps-6](./assets/steps-6.jpg)
@@ -56,7 +56,7 @@ The above logic is translated into code as follows:
5656
startPos,
5757
];
5858
return interpolate(
59-
handlerOffsetX.value,
59+
handlerOffset.value,
6060
inputRange,
6161
outputRange,
6262
Extrapolate.CLAMP
@@ -69,7 +69,7 @@ const inputRange = [-1, 0 ,1]
6969
const outputRange = [-size, 0 ,size]
7070
return {
7171
transform: [
72-
{ translateX: interpolate(handlerOffsetX.value, inputRange, outputRange) },
72+
{ translateX: interpolate(handlerOffset.value, inputRange, outputRange) },
7373
],
7474
}
7575
```

docs/about.zh-CN.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
2222
1. 首先我们需要一个单位`size`,它用来帮我们计算滚动距离,当水平时`size`等于`width` prop的设置,当垂直时`size`等于`height` prop的设置。
2323

24-
2. 其次我们需要一个值`handlerOffsetX`,用来记录当前的滚动距离,这是一个总值,当我们滚动两张,那`handlerOffsetX`等于size * 2,如果滚动十张那`handlerOffsetX`等于size * 10。
24+
2. 其次我们需要一个值`handlerOffset`,用来记录当前的滚动距离,这是一个总值,当我们滚动两张,那`handlerOffset`等于size * 2,如果滚动十张那`handlerOffset`等于size * 10。
2525

2626
3. 紧接着是处理如何让末尾的元素在合适的时候挪动到最前面,这部分逻辑在`./src/hooks/useOffsetX.ts`中。首先我们需要知道目前的视窗大小(一侧元素渲染的总数量),视窗大小默认为元素总数量的一半,即全量渲染。
2727
![steps-6](./assets/steps-6.jpg)
@@ -56,7 +56,7 @@
5656
startPos,
5757
];
5858
return interpolate(
59-
handlerOffsetX.value,
59+
handlerOffset.value,
6060
inputRange,
6161
outputRange,
6262
Extrapolate.CLAMP
@@ -69,7 +69,7 @@ const inputRange = [-1, 0 ,1]
6969
const outputRange = [-size, 0 ,size]
7070
return {
7171
transform: [
72-
{ translateX: interpolate(handlerOffsetX.value, inputRange, outputRange) },
72+
{ translateX: interpolate(handlerOffset.value, inputRange, outputRange) },
7373
],
7474
}
7575
```

docs/props.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
| name | required | default | types | description |
44
| ----------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
55
| data || | T[] | Carousel items data set |
6-
| renderItem || | (info: { data: T, index: number, animationValue: SharedValue\<number> }) => React.ReactElement | Render carousel item |
6+
| renderItem || | (info: { item: T, index: number, animationValue: SharedValue\<number> }) => React.ReactElement | Render carousel item |
7+
| defaultScrollOffsetValue|| useSharedValue<number>(0) | boolean | The default animated value of the carousel. |
78
| autoFillData || true | boolean | Auto fill data array to allow loop playback when the loop props is true.([1] => [1, 1, 1][1, 2] => [1, 2, 1, 2]) |
89
| vertical || false | boolean | Layout items vertically instead of horizontally |
910
| width | vertical ❌ horizontal ✅ | '100%' | number \| undefined | Specified carousel item width |

docs/props.zh-CN.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
| name | required | default | types | description |
44
| ----------------------- | ------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
55
| data || | T[] | 即将渲染的数据集合 |
6-
| renderItem || | (info: { data: T, index: number, animationValue: SharedValue\<number> }) => React.ReactElement | 渲染元素的方法 |
6+
| renderItem || | (info: { item: T, index: number, animationValue: SharedValue\<number> }) => React.ReactElement | 渲染元素的方法 |
7+
| defaultScrollOffsetValue|| useSharedValue<number>(0) | boolean | 轮播图的默认动画值 |
78
| autoFillData || true | boolean | 将会在`loop`属性设置为 true 时,自动填充 data 元素以满足 loop 循环效果([1] => [1, 1, 1][1, 2] => [1, 2, 1, 2]) |
89
| vertical || false | boolean | 将元素垂直布局而不是水平 |
910
| width | 垂直时 ❌ 水平时 ✅ | '100%' | number \| undefined | 指定每一项的宽度 |

src/Carousel.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,15 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
4848
} = props;
4949

5050
const commonVariables = useCommonVariables(props);
51-
const { size, handlerOffsetX } = commonVariables;
51+
const { size, handlerOffset } = commonVariables;
5252
const dataLength = data.length;
5353

5454
const offsetX = useDerivedValue(() => {
5555
const totalSize = size * dataLength;
56-
const x = handlerOffsetX.value % totalSize;
56+
const x = handlerOffset.value % totalSize;
5757

5858
if (!loop) {
59-
return handlerOffsetX.value;
59+
return handlerOffset.value;
6060
}
6161
return isNaN(x) ? 0 : x;
6262
}, [loop, size, dataLength]);
@@ -76,7 +76,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
7676
size,
7777
data,
7878
autoFillData,
79-
handlerOffsetX,
79+
handlerOffset,
8080
withAnimation,
8181
defaultIndex,
8282
onScrollEnd: () => runOnJS(_onScrollEnd)(),
@@ -151,7 +151,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
151151
const visibleRanges = useVisibleRanges({
152152
total: data.length,
153153
viewSize: size,
154-
translation: handlerOffsetX,
154+
translation: handlerOffset,
155155
windowSize,
156156
});
157157

@@ -170,7 +170,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
170170
<BaseLayout
171171
key={i}
172172
index={i}
173-
handlerOffsetX={offsetX}
173+
handlerOffset={offsetX}
174174
visibleRanges={visibleRanges}
175175
animationStyle={customAnimation || layoutConfig}
176176
>
@@ -201,7 +201,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
201201
<ScrollViewGesture
202202
key={mode}
203203
size={size}
204-
translation={handlerOffsetX}
204+
translation={handlerOffset}
205205
style={[
206206
styles.container,
207207
{

src/hooks/useCarouselController.tsx

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ interface IOpts {
2020
size: number;
2121
data: TCarouselProps['data'];
2222
autoFillData: TCarouselProps['autoFillData'];
23-
handlerOffsetX: Animated.SharedValue<number>;
23+
handlerOffset: Animated.SharedValue<number>;
2424
withAnimation?: TCarouselProps['withAnimation'];
2525
duration?: number;
2626
defaultIndex?: number;
@@ -41,7 +41,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
4141
size,
4242
data,
4343
loop,
44-
handlerOffsetX,
44+
handlerOffset,
4545
withAnimation,
4646
defaultIndex = 0,
4747
duration,
@@ -64,26 +64,26 @@ export function useCarouselController(options: IOpts): ICarouselController {
6464

6565
const currentFixedPage = React.useCallback(() => {
6666
if (loop) {
67-
return -Math.round(handlerOffsetX.value / size);
67+
return -Math.round(handlerOffset.value / size);
6868
}
6969

70-
const fixed = (handlerOffsetX.value / size) % dataInfo.length;
70+
const fixed = (handlerOffset.value / size) % dataInfo.length;
7171
return Math.round(
72-
handlerOffsetX.value <= 0
72+
handlerOffset.value <= 0
7373
? Math.abs(fixed)
7474
: Math.abs(fixed > 0 ? dataInfo.length - fixed : 0)
7575
);
76-
}, [handlerOffsetX, dataInfo, size, loop]);
76+
}, [handlerOffset, dataInfo, size, loop]);
7777

7878
function setSharedIndex(newSharedIndex: number) {
7979
sharedIndex.current = newSharedIndex;
8080
}
8181

8282
useAnimatedReaction(
8383
() => {
84-
const handlerOffsetXValue = handlerOffsetX.value;
85-
const toInt = round(handlerOffsetXValue / size) % dataInfo.length;
86-
const isPositive = handlerOffsetXValue <= 0;
84+
const handlerOffsetValue = handlerOffset.value;
85+
const toInt = round(handlerOffsetValue / size) % dataInfo.length;
86+
const isPositive = handlerOffsetValue <= 0;
8787
const i = isPositive
8888
? Math.abs(toInt)
8989
: Math.abs(toInt > 0 ? dataInfo.length - toInt : 0);
@@ -112,7 +112,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
112112
index,
113113
loop,
114114
autoFillData,
115-
handlerOffsetX,
115+
handlerOffset,
116116
]
117117
);
118118

@@ -169,12 +169,12 @@ export function useCarouselController(options: IOpts): ICarouselController {
169169
index.value = nextPage;
170170

171171
if (animated) {
172-
handlerOffsetX.value = scrollWithTiming(
172+
handlerOffset.value = scrollWithTiming(
173173
-nextPage * size,
174174
onFinished
175175
) as any;
176176
} else {
177-
handlerOffsetX.value = -nextPage * size;
177+
handlerOffset.value = -nextPage * size;
178178
onFinished?.();
179179
}
180180
},
@@ -184,7 +184,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
184184
index,
185185
dataInfo,
186186
onScrollBegin,
187-
handlerOffsetX,
187+
handlerOffset,
188188
size,
189189
scrollWithTiming,
190190
currentFixedPage,
@@ -202,12 +202,12 @@ export function useCarouselController(options: IOpts): ICarouselController {
202202
index.value = prevPage;
203203

204204
if (animated) {
205-
handlerOffsetX.value = scrollWithTiming(
205+
handlerOffset.value = scrollWithTiming(
206206
-prevPage * size,
207207
onFinished
208208
);
209209
} else {
210-
handlerOffsetX.value = -prevPage * size;
210+
handlerOffset.value = -prevPage * size;
211211
onFinished?.();
212212
}
213213
},
@@ -216,7 +216,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
216216
loop,
217217
index,
218218
onScrollBegin,
219-
handlerOffsetX,
219+
handlerOffset,
220220
size,
221221
scrollWithTiming,
222222
currentFixedPage,
@@ -231,13 +231,13 @@ export function useCarouselController(options: IOpts): ICarouselController {
231231

232232
onScrollBegin?.();
233233
// direction -> 1 | -1
234-
const isPositiveZero = Object.is(handlerOffsetX.value, +0);
235-
const isNegativeZero = Object.is(handlerOffsetX.value, -0);
234+
const isPositiveZero = Object.is(handlerOffset.value, +0);
235+
const isNegativeZero = Object.is(handlerOffset.value, -0);
236236
const direction = isPositiveZero
237237
? 1
238238
: isNegativeZero
239239
? -1
240-
: Math.sign(handlerOffsetX.value);
240+
: Math.sign(handlerOffset.value);
241241

242242
// target offset
243243
const offset = i * size * direction;
@@ -248,25 +248,22 @@ export function useCarouselController(options: IOpts): ICarouselController {
248248

249249
if (loop) {
250250
isCloseToNextLoop =
251-
Math.abs(handlerOffsetX.value % totalSize) / totalSize >=
251+
Math.abs(handlerOffset.value % totalSize) / totalSize >=
252252
0.5;
253253
}
254254

255255
const finalOffset =
256-
(Math.floor(Math.abs(handlerOffsetX.value / totalSize)) +
256+
(Math.floor(Math.abs(handlerOffset.value / totalSize)) +
257257
(isCloseToNextLoop ? 1 : 0)) *
258258
totalSize *
259259
direction +
260260
offset;
261261

262262
if (animated) {
263263
index.value = i;
264-
handlerOffsetX.value = scrollWithTiming(
265-
finalOffset,
266-
onFinished
267-
);
264+
handlerOffset.value = scrollWithTiming(finalOffset, onFinished);
268265
} else {
269-
handlerOffsetX.value = finalOffset;
266+
handlerOffset.value = finalOffset;
270267
index.value = i;
271268
onFinished?.();
272269
}
@@ -275,7 +272,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
275272
index,
276273
canSliding,
277274
onScrollBegin,
278-
handlerOffsetX,
275+
handlerOffset,
279276
size,
280277
dataInfo.length,
281278
loop,

src/hooks/useCommonVariables.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,33 @@ import type { TInitializeCarouselProps } from './useInitProps';
55
interface ICommonVariables {
66
size: number;
77
validLength: number;
8-
handlerOffsetX: Animated.SharedValue<number>;
8+
handlerOffset: Animated.SharedValue<number>;
99
}
1010

1111
export function useCommonVariables(
1212
props: TInitializeCarouselProps<any>
1313
): ICommonVariables {
14-
const { vertical, height, width, data, defaultIndex } = props;
14+
const {
15+
vertical,
16+
height,
17+
width,
18+
data,
19+
defaultIndex,
20+
defaultScrollOffsetValue,
21+
} = props;
1522
const size = vertical ? height : width;
1623
const validLength = data.length - 1;
17-
const defaultHandlerOffsetX = -Math.abs(defaultIndex * size);
18-
const handlerOffsetX = useSharedValue<number>(defaultHandlerOffsetX);
24+
const defaultHandlerOffsetValue = -Math.abs(defaultIndex * size);
25+
const _handlerOffset = useSharedValue<number>(defaultHandlerOffsetValue);
26+
const handlerOffset = defaultScrollOffsetValue ?? _handlerOffset;
1927

2028
React.useEffect(() => {
21-
handlerOffsetX.value = defaultHandlerOffsetX;
22-
}, [vertical, handlerOffsetX, defaultHandlerOffsetX]);
29+
handlerOffset.value = defaultHandlerOffsetValue;
30+
}, [vertical, handlerOffset, defaultHandlerOffsetValue]);
2331

2432
return {
2533
size,
2634
validLength,
27-
handlerOffsetX,
35+
handlerOffset,
2836
};
2937
}

0 commit comments

Comments
 (0)