react-native-flatlist-slider
react-native-flatlist-slider copied to clipboard
Created this Flatlist-slider using React Hooks and is working
import {
UIManager,
Platform,
Dimensions,
View,
FlatList,
ImageBackground,
Pressable,
} from "react-native";
import { Title } from "react-native-paper";
import styles from "./styles";
import { LinearGradient } from "expo-linear-gradient";
import { LOG } from "../../logging/config";
var logger = LOG.extend("OBJECT");
const ImageSlider = ({ sliderData, imageKey, titleKey, colorKey }) => {
const [index, setIndex] = useState(0);
const [data, setData] = useState(sliderData);
const [activeImage, setActiveImage] = useState(0);
const slider = useRef();
const timer = 4000; // Set scroll time
const itemHeight = 165;
const itemWidth = Dimensions.get("window").width;
const separatorWidth = 0;
const totalItemWidth = itemWidth + separatorWidth;
var currentIndexCallback = null;
var sliderTimer = null;
if (Platform.OS === "android") {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
useEffect(() => {
setData(sliderData);
if (sliderData.toString() !== data.toString()) {
setData(sliderData);
logger.info("useEffect|data length=", data.length);
}
startAutoPlay();
return () => {
stopAutoPlay();
};
}, [index, data, activeImage]);
const onViewableItemsChanged = useCallback((viewableItems, changed) => {
logger.info("onViewableItemsChanged|Entry");
logger.info("onViewableItemsChanged|viewableItems=" + viewableItems);
if (viewableItems) {
let currentIndex = viewableItems["changed"][0].index;
logger.info("onViewableItemsChanged|currentIndex=" + currentIndex);
logger.info("onViewableItemsChanged|temp=" + data.length);
if (currentIndex === sliderData.length - 1) {
logger.info("onViewableItemsChanged|End of loop");
setIndex(0);
setActiveImage(currentIndex);
} else {
setActiveImage(currentIndex);
}
if (currentIndexCallback) {
currentIndexCallback(currentIndex);
}
}
logger.info("onViewableItemsChanged|Exit");
}, []);
const viewabilityConfig = {
viewAreaCoveragePercentThreshold: 50,
};
const viewabilityConfigCallbackPairs = useRef([
{ viewabilityConfig, onViewableItemsChanged },
]);
const changeSliderListIndex = () => {
logger.info("changeSliderListIndex|Entry");
//LayoutAnimation.configureNext(LayoutAnimation.Presets.easeIn); //Not working
logger.info("changeSliderListIndex|index=" + index);
if (slider != null) {
setIndex(index + 1);
slider.current.scrollToIndex({
index: index,
animated: true,
});
logger.info("changeSliderListIndex|Slider Scrolled");
}
logger.info("changeSliderListIndex|Exit");
};
const startAutoPlay = () => {
logger.info("startAutoPlay|Entry");
sliderTimer = setInterval(() => changeSliderListIndex(), timer);
logger.info("startAutoPlay|Exit");
};
const stopAutoPlay = () => {
logger.info("stopAutoPlay|Entry");
if (sliderTimer) {
logger.info("stopAutoPlay|sliderTimer=True");
clearInterval(sliderTimer);
sliderTimer = null;
}
logger.info("stopAutoPlay|Exit");
};
return (
<View
style={{
width: itemWidth,
height: 165,
zIndex: -1,
resizeMode: "cover",
}}
>
<FlatList
ref={slider}
horizontal
pagingEnabled={true}
snapToInterval={totalItemWidth}
decelerationRate="fast"
bounces={false}
contentContainerStyle={styles.contentContainerStyle}
data={data}
showsHorizontalScrollIndicator={false}
renderItem={({ item, i }) => (
<ChildItem
width={itemWidth}
item={item}
colorKey={colorKey}
titleKey={titleKey}
imageKey={imageKey}
onPress={() => logger.info(item + "pressed")}
index={index % sliderData.length}
active={i === index}
local={false}
height={itemHeight}
/>
)}
ItemSeparatorComponent={() => (
<View style={{ width: separatorWidth }} />
)}
keyExtractor={(item, index) => item.toString() + index}
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs.current}
viewabilityConfig={viewabilityConfig}
getItemLayout={(data, index) => ({
length: totalItemWidth,
offset: totalItemWidth * index,
index,
})}
windowSize={1}
initialNumToRender={1}
maxToRenderPerBatch={1}
removeClippedSubviews={true}
/>
<View style={styles.circlesContainer}>
{data.map((i, k) => (
<View
key={k}
style={k == activeImage ? styles.circleActive : styles.circle}
/>
))}
</View>
</View>
);
};
const ChildItem = ({
item,
width,
onPress,
index,
colorKey,
titleKey,
imageKey,
local,
height,
}) => {
return (
<Pressable onPress={() => onPress(alert(`${item[titleKey]}`))}>
<ImageBackground
style={{
width: width,
height: height,
resizeMode: "cover",
}}
source={local ? item[imageKey] : { uri: item[imageKey] }}
>
<LinearGradient
key={index}
locations={[0.3, 1]}
colors={[
"transparent",
item[colorKey] == null ? "black" : item[colorKey],
]}
style={styles.linearGradient}
>
<View style={styles.imageTitleContainer}>
<Title numberOfLines={1} style={styles.imageTitle}>
{item[titleKey]}
</Title>
</View>
</LinearGradient>
</ImageBackground>
</Pressable>
);
};
export default ImageSlider;
import { Dimensions, StyleSheet } from "react-native";
import { LIGHTGREY } from "../../../assets/colors/colors";
import {
MARGINHEIGHTFIVE,
MARGINHEIGHTTEN,
MARGINWIDTHTEN,
} from "../../../constants/constants";
const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
const styles = StyleSheet.create({
contentContainerStyle: {},
linearGradient: {
flex: 1,
},
imageTitleContainer: {
width: windowWidth * (95 / 100),
paddingRight: 10,
marginTop: "auto",
marginBottom: MARGINHEIGHTTEN + MARGINHEIGHTFIVE,
},
imageTitle: {
fontFamily: "Lato-Bold",
fontSize: 20,
color: "#ffffff",
left: MARGINWIDTHTEN,
textShadowColor: "rgba(0, 0, 0, 0.75)",
textShadowOffset: { width: -1, height: 1 },
textShadowRadius: 3,
},
circlesContainer: {
flexDirection: "row",
position: "absolute",
bottom: 0,
alignSelf: "center",
marginVertical: windowHeight * (0.334 / 100),
},
circle: {
backgroundColor: LIGHTGREY,
opacity: 0.5,
height: 5,
width: 5,
borderRadius: 50,
marginHorizontal: windowWidth * (0.924 / 100),
},
circleActive: {
backgroundColor: "#ffffff",
height: 5,
width: 5,
borderRadius: 50,
marginHorizontal: windowWidth * (0.924 / 100),
},
});
export default styles;