react-native-flatlist-slider icon indicating copy to clipboard operation
react-native-flatlist-slider copied to clipboard

Created this Flatlist-slider using React Hooks and is working

Open wavydeer opened this issue 2 years ago • 0 comments


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;

wavydeer avatar Feb 11 '23 08:02 wavydeer