Skip to content

Commit d4460d5

Browse files
authored
Merge pull request #102 from dohooo/fix/carousel-controller
fix: fix useCarouselController
2 parents be109fd + 753051f commit d4460d5

File tree

14 files changed

+313
-229
lines changed

14 files changed

+313
-229
lines changed

docs/props.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454

5555
| name | types | description |
5656
| --------------- | ------------------------------------------- | ---------------------- |
57-
| prev | ()=>void | Play the last one |
58-
| loop | ()=>void | Play the next one |
59-
| goToIndex | (index: number, animated?: boolean) => void | Go to index |
57+
| prev | ({ count = 1, animated = false, onFinished?: () => void }) => void | Scroll to previous item, it takes one optional argument (count), which allows you to specify how many items to cross |
58+
| next | ({ count = 1, animated = false, onFinished?: () => void }) => void | Scroll to next item, it takes one optional argument (count), which allows you to specify how many items to cross |
59+
| scrollTo | ({ count = 1, animated = false, onFinished?: () => void }) => void | Use count to scroll to a position where relative to the current position, scrollTo(-2) is equivalent to prev(2), scrollTo(2) is equivalent to next(2) |
60+
| (deprecated)goToIndex | (index: number, animated?: boolean) => void | Go to index |
6061
| getCurrentIndex | ()=>number | Get current item index |

docs/props.zh-CN.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454

5555
| name | types | description |
5656
| --------------- | ------------------------------------------- | ------------------ |
57-
| prev | ()=>void | 切换至上一张 |
58-
| loop | ()=>void | 切换至下一张 |
59-
| goToIndex | (index: number, animated?: boolean) => void | 切换至指定下标元素 |
57+
| prev | ({ count = 1, animated = false, onFinished?: () => void }) => void | 切换至上一项,可以指定`count`决定切换的数量 |
58+
| next | ({ count = 1, animated = false, onFinished?: () => void }) => void | 切换至下一张,可以指定`count`决定切换的数量 |
59+
| scrollTo | ({ count = 1, animated = false, onFinished?: () => void }) => void | 切换到距离当前相对位置为`count`的位置,`scrollTo(-2)`等价于`prev(2)``scrollTo(2)`等价于`next(2)` |
60+
| (弃用)goToIndex | (index: number, animated?: boolean) => void | 切换至指定下标元素 |
6061
| getCurrentIndex | ()=>number | 获得当前轮播图下标 |

example/src/advanced-parallax/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ function Index() {
5252
);
5353
}}
5454
customAnimation={animationStyle}
55+
scrollAnimationDuration={1200}
5556
/>
5657
<SButton
5758
onPress={() => {

example/src/anim-tab-bar/index.tsx

Lines changed: 137 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,158 @@
11
import * as React from 'react';
2-
import { Extrapolate, interpolate } from 'react-native-reanimated';
3-
import Carousel from 'react-native-reanimated-carousel';
4-
import { View, Text } from 'react-native-ui-lib';
5-
import type { TAnimationStyle } from '../../../src/layouts/BaseLayout';
2+
import { Pressable } from 'react-native';
3+
import Animated, {
4+
Extrapolate,
5+
interpolate,
6+
interpolateColor,
7+
useAnimatedStyle,
8+
useSharedValue,
9+
withTiming,
10+
} from 'react-native-reanimated';
11+
import Carousel, { ICarouselInstance } from 'react-native-reanimated-carousel';
12+
import { Colors, View } from 'react-native-ui-lib';
13+
import SButton from '../components/SButton';
614
import { ElementsText, window } from '../constants';
715
import { useToggleButton } from '../hooks/useToggleButton';
816

9-
const PAGE_WIDTH = 40;
17+
const PAGE_WIDTH = 60;
1018
const PAGE_HEIGHT = 40;
19+
const DATA = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
1120

1221
function Index() {
22+
const r = React.useRef<ICarouselInstance>(null);
1323
const AutoPLay = useToggleButton({
1424
defaultValue: false,
1525
buttonTitle: ElementsText.AUTOPLAY,
1626
});
17-
18-
const animationStyle: TAnimationStyle = React.useCallback(
19-
(value: number) => {
20-
'worklet';
21-
22-
const translateX = interpolate(
23-
value,
24-
[-1, 0, 1],
25-
[-PAGE_WIDTH, 0, PAGE_WIDTH]
26-
);
27-
28-
const opacity = interpolate(
29-
value,
30-
[-1, 0, 1],
31-
[0.5, 1, 0.5],
32-
Extrapolate.CLAMP
33-
);
34-
35-
const scale = interpolate(
36-
value,
37-
[-1, 0, 1],
38-
[0.8, 1.4, 0.8],
39-
Extrapolate.CLAMP
40-
);
41-
42-
return {
43-
transform: [{ translateX }, { scale }],
44-
opacity,
45-
};
46-
},
47-
[]
48-
);
27+
const [loop, setLoop] = React.useState(false);
4928

5029
return (
5130
<View style={{ flex: 1 }}>
52-
<Carousel
53-
loop={false}
31+
<View style={{ marginVertical: 100 }}>
32+
<Carousel
33+
key={`${loop}`}
34+
ref={r}
35+
loop={loop}
36+
style={{
37+
width: window.width,
38+
height: PAGE_HEIGHT,
39+
justifyContent: 'center',
40+
alignItems: 'center',
41+
borderBottomWidth: 1,
42+
borderBottomColor: Colors.blue30,
43+
}}
44+
width={PAGE_WIDTH}
45+
height={PAGE_HEIGHT}
46+
data={DATA}
47+
renderItem={({ item, animationValue }) => {
48+
return (
49+
<Item
50+
animationValue={animationValue}
51+
label={item}
52+
onPress={() =>
53+
r.current?.scrollTo({
54+
count: animationValue.value,
55+
animated: true,
56+
})
57+
}
58+
/>
59+
);
60+
}}
61+
autoPlay={AutoPLay.status}
62+
/>
63+
</View>
64+
{AutoPLay.button}
65+
<SButton onPress={() => setLoop(!loop)}>{`Loop: ${loop}`}</SButton>
66+
<View
5467
style={{
55-
width: window.width,
56-
justifyContent: 'center',
57-
alignItems: 'center',
58-
paddingVertical: 110,
59-
}}
60-
width={PAGE_WIDTH}
61-
height={PAGE_HEIGHT}
62-
data={['周一', '周二', '周三', '周四', '周五', '周六', '周日']}
63-
renderItem={({ item }) => {
64-
return (
65-
<View center height={'100%'}>
66-
<Text color={'#26292E'}>{item}</Text>
67-
</View>
68-
);
68+
marginTop: 24,
69+
flexDirection: 'row',
70+
justifyContent: 'space-evenly',
6971
}}
70-
autoPlay={AutoPLay.status}
71-
customAnimation={animationStyle}
72-
/>
73-
{AutoPLay.button}
72+
>
73+
<SButton onPress={() => r.current?.prev()}>{'Prev'}</SButton>
74+
<SButton onPress={() => r.current?.next()}>{'Next'}</SButton>
75+
</View>
7476
</View>
7577
);
7678
}
7779

7880
export default Index;
81+
82+
interface Props {
83+
animationValue: Animated.SharedValue<number>;
84+
label: string;
85+
onPress?: () => void;
86+
}
87+
88+
const Item: React.FC<Props> = (props) => {
89+
const { animationValue, label, onPress } = props;
90+
91+
const translateY = useSharedValue(0);
92+
93+
const containerStyle = useAnimatedStyle(() => {
94+
const opacity = interpolate(
95+
animationValue.value,
96+
[-1, 0, 1],
97+
[0.5, 1, 0.5],
98+
Extrapolate.CLAMP
99+
);
100+
101+
return {
102+
opacity,
103+
};
104+
}, [animationValue]);
105+
106+
const labelStyle = useAnimatedStyle(() => {
107+
const scale = interpolate(
108+
animationValue.value,
109+
[-1, 0, 1],
110+
[1, 1.25, 1],
111+
Extrapolate.CLAMP
112+
);
113+
114+
const color = interpolateColor(
115+
animationValue.value,
116+
[-1, 0, 1],
117+
[Colors.grey30, Colors.blue30, Colors.grey30]
118+
);
119+
120+
return {
121+
transform: [{ scale }, { translateY: translateY.value }],
122+
color,
123+
};
124+
}, [animationValue, translateY]);
125+
126+
const onPressIn = React.useCallback(() => {
127+
translateY.value = withTiming(-8, { duration: 250 });
128+
}, [translateY]);
129+
130+
const onPressOut = React.useCallback(() => {
131+
translateY.value = withTiming(0, { duration: 250 });
132+
}, [translateY]);
133+
134+
return (
135+
<Pressable
136+
onPress={onPress}
137+
onPressIn={onPressIn}
138+
onPressOut={onPressOut}
139+
>
140+
<Animated.View
141+
style={[
142+
{
143+
height: '100%',
144+
alignItems: 'center',
145+
justifyContent: 'center',
146+
},
147+
containerStyle,
148+
]}
149+
>
150+
<Animated.Text
151+
style={[{ fontSize: 18, color: '#26292E' }, labelStyle]}
152+
>
153+
{label}
154+
</Animated.Text>
155+
</Animated.View>
156+
</Pressable>
157+
);
158+
};

example/src/hooks/useToggleButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export function useToggleButton(opts: {
1111
const button = React.useMemo(() => {
1212
return (
1313
<SButton onPress={() => setStatus(!status)}>
14-
{buttonTitle}:{`${status}`}
14+
{buttonTitle}: {`${status}`}
1515
</SButton>
1616
);
1717
}, [status, buttonTitle]);

example/src/normal/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function Index() {
3030
{...baseOptions}
3131
loop
3232
autoPlay={isAutoPlay}
33-
autoPlayInterval={isFast ? 100 : 1500}
33+
autoPlayInterval={isFast ? 100 : 2000}
3434
data={[...new Array(6).keys()]}
3535
renderItem={({ index }) => <SBItem key={index} index={index} />}
3636
/>

example/src/pause-advanced-parallax/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ function Index() {
5252
);
5353
}}
5454
customAnimation={animationStyle}
55+
scrollAnimationDuration={1200}
5556
/>
5657
<SButton
5758
onPress={() => {

src/Carousel.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function Carousel<T>(
6969
originalLength: data.length,
7070
onScrollEnd: () => runOnJS(_onScrollEnd)(),
7171
onScrollBegin: () => !!onScrollBegin && runOnJS(onScrollBegin)(),
72-
onChange: (i) => onSnapToItem && runOnJS(onSnapToItem)(i),
72+
onChange: (i) => !!onSnapToItem && runOnJS(onSnapToItem)(i),
7373
duration: scrollAnimationDuration,
7474
});
7575

@@ -82,7 +82,7 @@ function Carousel<T>(
8282
getCurrentIndex,
8383
} = carouselController;
8484

85-
const { run, pause } = useAutoPlay({
85+
const { start, pause } = useAutoPlay({
8686
autoPlay,
8787
autoPlayInterval,
8888
autoPlayReverse,
@@ -100,9 +100,9 @@ function Carousel<T>(
100100
}, [sharedPreIndex, sharedIndex, computedIndex, onScrollEnd]);
101101

102102
const scrollViewGestureOnScrollEnd = React.useCallback(() => {
103-
run();
103+
start();
104104
_onScrollEnd();
105-
}, [_onScrollEnd, run]);
105+
}, [_onScrollEnd, start]);
106106

107107
const goToIndex = React.useCallback(
108108
(i: number, animated?: boolean) => {
@@ -118,8 +118,9 @@ function Carousel<T>(
118118
prev,
119119
getCurrentIndex,
120120
goToIndex,
121+
scrollTo: carouselController.scrollTo,
121122
}),
122-
[getCurrentIndex, goToIndex, next, prev]
123+
[getCurrentIndex, goToIndex, next, prev, carouselController.scrollTo]
123124
);
124125

125126
const visibleRanges = useVisibleRanges({

src/ScrollViewGesture.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
4141
enableSnap,
4242
panGestureHandlerProps,
4343
loop: infinite,
44-
autoPlayInterval,
44+
scrollAnimationDuration,
4545
},
4646
} = React.useContext(CTX);
4747

@@ -59,7 +59,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
5959
return withTiming(
6060
toValue,
6161
{
62-
duration: autoPlayInterval,
62+
duration: scrollAnimationDuration,
6363
easing: Easing.easeOutQuart,
6464
},
6565
(isFinished) => {
@@ -69,7 +69,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
6969
}
7070
);
7171
},
72-
[autoPlayInterval]
72+
[scrollAnimationDuration]
7373
);
7474

7575
const endWithSpring = React.useCallback(

0 commit comments

Comments
 (0)