[英]how can I make a custom carousel or image slide in react native without using any npm packages
我在不使用任何包的情况下在本机反应中制作自定义图像轮播或图像滑块,问题是底部的点指示器在 3 秒间隔后变化良好,但图像不会自动滑动。 有一些我找不到的小问题。 如果您可以在不更改大部分代码的情况下帮助解决此问题,那就太好了。 提前致谢。
这是完整的组件代码。
import React, {useEffect, useState, useRef} from 'react';
import {StyleSheet, ScrollView, View, Dimensions, Text} from 'react-native';
import {ActivityIndicator} from 'react-native';
import {Image} from 'react-native-elements';
const HomeCarousel = () => {
const [dimension, setDimension] = useState(Dimensions.get('window'));
const [selectedIndex, setSelectedIndex] = useState(0);
const scrollRef = useRef();
const onChange = () => {
setDimension(Dimensions.get('window'));
};
useEffect(() => {
Dimensions.addEventListener('change', onChange);
return () => {
Dimensions.removeEventListener('change', onChange);
};
});
useEffect(() => {
setInterval(() => {
setSelectedIndex(prevSelectedIndex =>
prevSelectedIndex === carouselImages.length - 1
? 0
: prevSelectedIndex + 1,
);
() => {
scrollRef.current.scrollTo({
animated: true,
y: 0,
x: dimension.width * selectedIndex,
});
};
}, 3000);
}, []);
const carouselImages = [
{url: 'https://i.ibb.co/FDwNR9d/img1.jpg'},
{url: 'https://i.ibb.co/7G5qqGY/1.jpg'},
{url: 'https://i.ibb.co/Jx7xqf4/pexels-august-de-richelieu-4427816.jpg'},
{url: 'https://i.ibb.co/GV08J9f/pexels-pixabay-267202.jpg'},
{url: 'https://i.ibb.co/sK92ZhC/pexels-karolina-grabowska-4210860.jpg'},
];
const setIndex = event => {
let viewSize = event.nativeEvent.layoutMeasurement.width;
let contentOffset = event.nativeEvent.contentOffset.x;
let carouselIndex = Math.floor(contentOffset / viewSize);
setSelectedIndex(carouselIndex);
};
return (
<View style={{width: dimension.width}}>
<ScrollView
horizontal
ref={scrollRef}
onMomentumScrollEnd={setIndex}
showsHorizontalScrollIndicator={false}
pagingEnabled>
{carouselImages.map((value, key) => (
<Image
source={{uri: `${value.url}`}}
style={{width: dimension?.width, height: 250, resizeMode: 'cover'}}
PlaceholderContent={<ActivityIndicator />}
/>
))}
</ScrollView>
<View
style={{
flexDirection: 'row',
position: 'absolute',
bottom: 0,
alignSelf: 'center',
}}>
{carouselImages.map((val, key) => (
<Text
key={key}
style={key === selectedIndex ? {color: 'white'} : {color: '#888'}}>
⬤
</Text>
))}
</View>
</View>
);
};
const styles = StyleSheet.create({});
export default HomeCarousel;
由于两件事,您的图像没有更新:
// You're just defining the function here and not actually calling it
() => {
scrollRef.current.scrollTo({
animated: true,
y: 0,
x: dimension.width * selectedIndex,
});
};
useEffect
没有任何依赖关系,这意味着它的回调不会改变,因此其中的selectedIndex
将始终为 0:useEffect(() => {
setInterval(() => {
setSelectedIndex(prevSelectedIndex =>
prevSelectedIndex === carouselImages.length - 1
? 0
: prevSelectedIndex + 1,
);
() => {
scrollRef.current.scrollTo({
animated: true,
y: 0,
// Since there are no dependencies, this callback won't ever be changed and selectedIndex will always be 0
x: dimension.width * selectedIndex,
});
};
}, 3000);
// You have no dependencies here
}, []);
我对改进/修复的建议是:
useEffect
回调中更新幻灯片并应用带有selectedIndex
依赖项的useCallback
挂钩。 您还应该在setSelectedIndex
挂钩之外计算新索引的值,因为setState/useState
不会立即更新:// You should also use an intervalId so that you can clear the interval/reset when needed
let intervalId = null;
const HomeCarousel = () => {
// ... rest of the HomeCarousel component
const onSlideChange = useCallback(() => {
// Calculate newIndex here and use it to update your state and to scroll to the new slide
const newIndex = selectedIndex === carouselImages.length - 1 ? 0 : selectedIndex + 1;
setSelectedIndex(newIndex);
scrollRef?.current?.scrollTo({
animated: true,
y: 0,
x: dimension.width * newIndex,
});
}, [selectedIndex]);
const startInterval = useCallback(() => {
intervalId = setInterval(onSlideChange, 3000);
}, [onSlideChange]);
useEffect(() => {
startInterval();
return () => {
// Clear the interval when component unmounts, otherwise you could have memory leaks
clearInterval(intervalId);
};
}, [onSlideChange]);
// ... rest of the HomeCarousel component
};
const onTouchStart = () => {
// As soon as the user touches the slide, stop the automatic sliding
clearInterval(intervalId);
};
const onTouchEnd = () => {
// As soon as the user stops touching the slide, releases it, start the automatic sliding again
startInterval();
};
return (
<ScrollView
// ... Other scrollview props
onTouchStart={onTouchStart}
onTouchEnd={onTouchEnd}>
{/* ... Rest of the component */}
const carouselImages = [ carousel1, carousel2, carousel3, carousel4, carousel5 ]; const Carousel = () => { const [current, setCurrent] = useState(0); useEffect(() => { const next = (current + 1) % carouselImages.length; const id = setTimeout(() => setCurrent(next), 3000); return () => clearTimeout(id); }, [current]); return ( <div className="banner"> <div className="slider"> <img src={carouselImages[current]} alt="carousel" /> </div> <div className="overlay"></div> </div> );
这是完整的工作代码。
import React, {useEffect, useState, useRef, useCallback} from 'react';
import {StyleSheet, ScrollView, View, Dimensions, Text} from 'react-native';
import {ActivityIndicator} from 'react-native';
import {Image} from 'react-native-elements';
const HomeCarousel = () => {
const [dimension, setDimension] = useState(Dimensions.get('window'));
const [selectedIndex, setSelectedIndex] = useState(0);
const scrollRef = useRef();
let intervalId = null;
const onChange = () => {
setDimension(Dimensions.get('window'));
};
useEffect(() => {
Dimensions.addEventListener('change', onChange);
return () => {
Dimensions.removeEventListener('change', onChange);
};
});
const onSlideChange = useCallback(() => {
// Calculate newIndex here and use it to update your state and to scroll to the new slide
const newIndex =
selectedIndex === carouselImages.length - 1 ? 0 : selectedIndex + 1;
setSelectedIndex(newIndex);
scrollRef?.current?.scrollTo({
animated: true,
y: 0,
x: dimension.width * newIndex,
});
}, [selectedIndex]);
const startInterval = useCallback(() => {
intervalId = setInterval(onSlideChange, 3000);
}, [onSlideChange]);
useEffect(() => {
startInterval();
return () => {
// Clear the interval when component unmounts, otherwise you could have memory leaks
clearInterval(intervalId);
};
}, [onSlideChange]);
const onTouchStart = () => {
// As soon as the user touches the slide, stop the automatic sliding
clearInterval(intervalId);
};
const onTouchEnd = () => {
// As soon as the user stops touching the slide, releases it, start the automatic sliding again
startInterval();
};
const carouselImages = [
{url: 'https://i.ibb.co/FDwNR9d/img1.jpg'},
{url: 'https://i.ibb.co/7G5qqGY/1.jpg'},
{url: 'https://i.ibb.co/Jx7xqf4/pexels-august-de-richelieu-4427816.jpg'},
{url: 'https://i.ibb.co/GV08J9f/pexels-pixabay-267202.jpg'},
{url: 'https://i.ibb.co/sK92ZhC/pexels-karolina-grabowska-4210860.jpg'},
];
const setIndex = event => {
let viewSize = event.nativeEvent.layoutMeasurement.width;
let contentOffset = event.nativeEvent.contentOffset.x;
let carouselIndex = Math.floor(contentOffset / viewSize);
setSelectedIndex(carouselIndex);
};
return (
<View style={{width: dimension.width}}>
<ScrollView
horizontal
ref={scrollRef}
onMomentumScrollEnd={setIndex}
showsHorizontalScrollIndicator={false}
onTouchStart={onTouchStart}
onTouchEnd={onTouchEnd}
pagingEnabled>
{carouselImages.map((value, key) => (
<Image
source={{uri: `${value.url}`}}
style={{width: dimension?.width, height: 250, resizeMode: 'cover'}}
PlaceholderContent={<ActivityIndicator />}
/>
))}
</ScrollView>
<View
style={{
flexDirection: 'row',
position: 'absolute',
bottom: 0,
alignSelf: 'center',
}}>
{carouselImages.map((val, key) => (
<Text
key={key}
style={key === selectedIndex ? {color: 'white'} : {color: '#888'}}>
⬤
</Text>
))}
</View>
</View>
);
};
const styles = StyleSheet.create({});
export default HomeCarousel;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.