UNPKG

rn-faded-flatlist

Version:

A simple and customizable React Native component that allows you to add fade effect in FlatView at both ends.

244 lines (233 loc) 7.01 kB
import React, { Component } from "react"; import { FlatList, View, Platform } from "react-native"; import PropTypes from "prop-types"; import LinearGradient from "react-native-linear-gradient"; const defaultFadeColors = [ "rgba(229, 229, 229, 0.18)", "rgba(206, 201, 201, 0.6)", "rgba(206, 201, 201, 0.9)", ]; export default class RNFadedFlatList extends Component { constructor(props) { super(props); this.state = { // We don't know the size of the content initially, and the probably won't instantly try to scroll, // so set the initial content height and width to 0 scrollHeight: 0, scrollWidth: 0, availableWidth: 0, availableHeight: 0, allowStartFade: false, allowEndFade: true, }; } onContentSizeChange = (contentWidth, contentHeight) => { // Save the content height in state this.setState({ scrollHeight: contentHeight, scrollWidth: contentWidth }); }; _onLayout(event) { const containerWidth = event.nativeEvent.layout.width; const containerHeight = event.nativeEvent.layout.height; this.setState({ availableWidth: containerWidth, availableHeight: containerHeight, }); } isEndFadeAllowed() { const sizeToCompare = this.props.horizontal ? this.state.scrollWidth : this.state.scrollHeight; const availableSpace = this.props.horizontal ? this.state.availableWidth : this.state.availableHeight; return this.props.allowEndFade ? sizeToCompare > availableSpace : false; } ifCloseToStart({ layoutMeasurement, contentOffset, contentSize }) { return this.props.horizontal ? contentOffset.x < this.props.scrollThreshold : contentOffset.y < this.props.scrollThreshold; } isCloseToBottom({ layoutMeasurement, contentOffset, contentSize }) { return this.props.horizontal ? layoutMeasurement.width + contentOffset.x >= contentSize.width - this.props.scrollThreshold : layoutMeasurement.height + contentOffset.y >= contentSize.height - this.props.scrollThreshold; } //To avoid FlatList RTL issue on android. allowReverse() { return Platform.OS == "android" && this.props.isRtl; } onScrolled = (e) => { if (this.props.isCloseToEnd) { this.props.isCloseToEnd(this.isCloseToBottom(e.nativeEvent)); } if (this.props.isCloseToStart) { this.props.isCloseToStart(this.ifCloseToStart(e.nativeEvent)); } if (this.props.allowStartFade) { if (!this.allowReverse()) { this.setState({ allowStartFade: this.ifCloseToStart(e.nativeEvent) ? false : true, }); } else { this.setState({ allowEndFade: this.ifCloseToStart(e.nativeEvent) ? false : true, }); } } if (this.props.allowEndFade) { if (!this.allowReverse()) { this.setState({ allowEndFade: this.isCloseToBottom(e.nativeEvent) ? false : true, }); } else { this.setState({ allowStartFade: this.isCloseToBottom(e.nativeEvent) ? false : true, }); } } if (this.props.onScroll) { this.props.onScroll(); } }; //get start fade view getStartFade() { return this.props.horizontal ? ( <LinearGradient start={{ x: this.props.isRtl ? 0 : 1, y: 0 }} end={{ x: this.props.isRtl ? 1 : 0, y: 0 }} style={[ { position: "absolute", start: 0, width: this.props.fadeSize, height: "100%", }, this.props.startFadeStyle, ]} colors={this.props.fadeColors} pointerEvents={"none"} /> ) : ( <LinearGradient start={{ x: 0, y: 1 }} end={{ x: 0, y: 0 }} style={[ { position: "absolute", top: 0, width: "100%", height: this.props.fadeSize, }, this.props.startFadeStyle, ]} colors={this.props.fadeColors} pointerEvents={"none"} /> ); } getEndFade() { return this.props.horizontal ? ( <LinearGradient start={{ x: this.props.isRtl ? 1 : 0, y: 0 }} end={{ x: this.props.isRtl ? 0 : 1, y: 0 }} style={[ { position: "absolute", end: 0, width: this.props.fadeSize, height: "100%", }, this.props.endFadeStyle, ]} colors={this.props.fadeColors} pointerEvents={"none"} /> ) : ( <LinearGradient start={{ x: 0, y: 0 }} end={{ x: 0, y: 1 }} style={[ { position: "absolute", bottom: 0, width: "100%", height: this.props.fadeSize, }, this.props.endFadeStyle, ]} colors={this.props.fadeColors} pointerEvents={"none"} /> ); } getDivider() { return this.props.horizontal ? ( <View style={[ { width: 1, height: "100%", backgroundColor: "#E6E6E6" }, this.props.dividerStyle, ]} /> ) : ( <View style={[ { width: "100%", height: 1, backgroundColor: "#E6E6E6" }, this.props.dividerStyle, ]} /> ); } render() { const endFadeEnable = this.isEndFadeAllowed(); return ( <View style={[ this.props.containerStyle, { flexDirection: this.props.horizontal ? "row" : "column" }, ]} onLayout={this._onLayout.bind(this)} > {this.state.allowStartFade && this.props.allowDivider && this.getDivider()} <FlatList {...this.props} style={[this.props.style]} onContentSizeChange={this.onContentSizeChange} scrollEventThrottle={16} onScroll={this.onScrolled} > {this.props.children} </FlatList> {endFadeEnable && this.state.allowEndFade && this.props.allowDivider && this.getDivider()} {this.state.allowStartFade && this.getStartFade()} {endFadeEnable && this.state.allowEndFade && this.getEndFade()} </View> ); } } RNFadedFlatList.propTypes = { allowStartFade: PropTypes.bool, allowEndFade: PropTypes.bool, fadeSize: PropTypes.number, fadeColors: PropTypes.array, isCloseToEnd: PropTypes.func, isCloseToStart: PropTypes.func, scrollThreshold: PropTypes.number, allowDivider: PropTypes.bool, isRtl: PropTypes.bool, }; RNFadedFlatList.defaultProps = { allowStartFade: false, allowEndFade: true, fadeSize: 20, fadeColors: defaultFadeColors, scrollThreshold: 10, allowDivider: false, isRtl: false, };