Created
November 10, 2017 20:48
-
-
Save asgvard/1951f0c1f81d47b5b286228e01d34271 to your computer and use it in GitHub Desktop.
Horizontal Paging Swiper based on FlatList
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* TODO Finish this for optimized Android swiping | |
* Inspired by react-native-swiper but based on cross-platform and optimized FlatList | |
*/ | |
import React, {Component} from 'react'; | |
import PropTypes from 'prop-types'; | |
import { | |
StyleSheet, | |
FlatList, | |
View | |
} from 'react-native'; | |
import {DEVICE_HEIGHT, DEVICE_WIDTH} from '../../utils/device'; | |
import AppColors from '../../styles/styles'; | |
import {dummy} from '../../utils/generic'; | |
import {isAndroid} from '../../utils/platform'; | |
const styles = StyleSheet.create({ | |
container: { | |
backgroundColor: AppColors.transparent, | |
flex: 1 | |
} | |
}); | |
class FlatSwiper extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
width: DEVICE_WIDTH, | |
height: DEVICE_HEIGHT, | |
index: 0 | |
}; | |
this.listRef = null; | |
this.onLayout = this.onLayout.bind(this); | |
this.onTouchStart = this.onTouchStart.bind(this); | |
this.onTouchEnd = this.onTouchEnd.bind(this); | |
this.onScrollEnd = this.onScrollEnd.bind(this); | |
this.getItemLayout = this.getItemLayout.bind(this); | |
this.onRefReady = this.onRefReady.bind(this); | |
this.renderItem = this.renderItem.bind(this); | |
this.scrollToIndex = this.scrollToIndex.bind(this); | |
} | |
onLayout({nativeEvent: {layout: {width, height}}}) { | |
this.setState({ | |
width, | |
height | |
}); | |
} | |
onTouchStart() { | |
console.log('onTouchStart'); | |
this.props.onTouchStart(); | |
} | |
onTouchEnd() { | |
console.log('onTouchEnd'); | |
this.props.onTouchEnd(); | |
} | |
onScrollEnd({nativeEvent: {contentOffset: {x}}}) { | |
console.log('onScrollEnd'); | |
const newIndex = this.state.width > 0 ? Math.ceil(x / this.state.width) : 0; | |
if (newIndex !== this.state.index) { | |
this.setState({ | |
index: newIndex | |
}, () => { | |
this.props.onIndexChange(newIndex); | |
}); | |
} | |
} | |
onRefReady(reference) { | |
reference && (this.listRef = reference); | |
} | |
getItemLayout(data, index) { | |
return { | |
length: this.state.width, | |
offset: this.state.width * index, | |
index | |
}; | |
} | |
scrollToIndex(index) { | |
console.log('scrollToIndex'); | |
this.listRef && this.listRef.scrollToIndex({index}); | |
/** | |
* Android hack to manually trigger onScrollEnd | |
* It doesn't trigger when manually scrolling | |
* <3 Android | |
*/ | |
isAndroid() && this.onScrollEnd({ | |
nativeEvent: { | |
contentOffset: { | |
x: index * this.state.width | |
} | |
} | |
}); | |
} | |
renderItem({item, index}) { | |
const {state: {width, height}} = this; | |
const itemWrapperStyle = { | |
width, | |
height | |
}; | |
return (<View style={itemWrapperStyle}> | |
{this.props.renderItem(item, index)} | |
</View>); | |
} | |
render() { | |
return (<FlatList | |
style={styles.container} | |
onLayout={this.onLayout} | |
data={this.props.data} | |
extraData={this.props.extraData} | |
pagingEnabled | |
horizontal | |
showsHorizontalScrollIndicator={false} | |
onTouchStart={this.onTouchStart} | |
onTouchEnd={this.onTouchEnd} | |
onMomentumScrollEnd={this.onScrollEnd} | |
onScrollBeginDrag={() => console.log('onScrollBeginDrag')} | |
onScrollEndDrag={() => console.log('onScrollEndDrag')} | |
onMomentumScrollBegin={() => console.log('onMomentumScrollBegin')} | |
onScrollShouldSetResponder={() => console.log('onScrollShouldSetResponder')} | |
onStartShouldSetResponder={() => console.log('onStartShouldSetResponder')} | |
onStartShouldSetResponderCapture={() => console.log('onStartShouldSetResponderCapture')} | |
onResponderGrant={() => console.log('onResponderGrant')} | |
onResponderReject={() => console.log('onResponderReject')} | |
onResponderRelease={() => console.log('onResponderRelease')} | |
onResponderTerminate={() => console.log('onResponderTerminate')} | |
onResponderTerminationRequest={() => console.log('onResponderTerminationRequest')} | |
onScroll={() => console.log('onScroll')} | |
keyExtractor={this.props.itemKeyExtractor} | |
getItemLayout={this.getItemLayout} | |
ref={this.onRefReady} | |
renderItem={this.renderItem} | |
/>); | |
} | |
} | |
FlatSwiper.propTypes = { | |
data: PropTypes.array.isRequired, | |
extraData: PropTypes.any, | |
onTouchStart: PropTypes.func, | |
onTouchEnd: PropTypes.func, | |
onIndexChange: PropTypes.func, | |
itemKeyExtractor: PropTypes.func.isRequired, | |
renderItem: PropTypes.func.isRequired | |
}; | |
FlatSwiper.defaultProps = { | |
extraData: null, | |
onTouchStart: dummy, | |
onTouchEnd: dummy, | |
onIndexChange: dummy | |
}; | |
export default FlatSwiper; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment