|
|
/**
|
|
|
* HomeBanner.js
|
|
|
*@author Alex
|
|
|
*@createtime 2020/6/3
|
|
|
*@description product banner images for allicance home page
|
|
|
*/
|
|
|
|
|
|
import React from 'react'
|
|
|
import {
|
|
|
Text,
|
|
|
View,
|
|
|
StyleSheet,
|
|
|
TouchableOpacity,
|
|
|
NativeModules,
|
|
|
DeviceEventEmitter,
|
|
|
FlatList,
|
|
|
Dimensions
|
|
|
} from 'react-native'
|
|
|
|
|
|
const IS_IOS = Platform.OS == 'ios' ? true : false
|
|
|
import SingleFocusProduct from './SingleFocusProduct';
|
|
|
|
|
|
export const DEVICE_WIDTH = Dimensions.get('window').width;
|
|
|
const {UIManager} = NativeModules
|
|
|
|
|
|
UIManager.setLayoutAnimationEnabledExperimental &&
|
|
|
UIManager.setLayoutAnimationEnabledExperimental(true);
|
|
|
|
|
|
export default class ProductFocus extends React.Component {
|
|
|
constructor(props) {
|
|
|
super(props)
|
|
|
|
|
|
this.pageControl = null;
|
|
|
try {
|
|
|
this.isTouching = false;
|
|
|
this.alreadyRendered = false;
|
|
|
this.scrollingRight = true;
|
|
|
let _total = props.data && props.data.length || 0;
|
|
|
this._total = _total;
|
|
|
let _data = props.data;
|
|
|
if (_total > 1) {
|
|
|
let tail = [_data[_total - 2], _data[_total - 1]];
|
|
|
let head = [_data[0], _data[1]];
|
|
|
_data = tail.concat(_data, head);
|
|
|
}
|
|
|
this.state = {
|
|
|
scrollEnabled: _total > 1 ? true : false,
|
|
|
contentOffset: {y: 0, x: _total > 1 ? 2 * (DEVICE_WIDTH-30) : 0},
|
|
|
currentPage: 0,
|
|
|
data: _data
|
|
|
}
|
|
|
this.lastx = _total > 1 ? 2 * (DEVICE_WIDTH-30) : 0;
|
|
|
} catch (e) {
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
try {
|
|
|
if (this.props.data && nextProps.data && !_.isEqual(this.props.data, nextProps.data)) {
|
|
|
this.stopAutoScroll();
|
|
|
let _total = nextProps.data && nextProps.data.length || 0;
|
|
|
this._total = _total;
|
|
|
let _data = nextProps.data;
|
|
|
if (_total > 1) {
|
|
|
let tail = [_data[_total - 2], _data[_total - 1]];
|
|
|
let head = [_data[0], _data[1]];
|
|
|
_data = tail.concat(_data, head);
|
|
|
} else {
|
|
|
this.setState({scrollEnabled: false});
|
|
|
}
|
|
|
this.setState({data: _data});
|
|
|
}
|
|
|
} catch (e) {
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
componentDidMount() {
|
|
|
this.subscription = DeviceEventEmitter.addListener('startAutoScroll', () => this.startAutoScroll('startAutoScroll'));
|
|
|
this.subscription1 = DeviceEventEmitter.addListener('stopAutoScroll', () => this.stopAutoScroll('stopAutoScroll'));
|
|
|
}
|
|
|
|
|
|
componentDidUpdate(prevProps, prevState) {
|
|
|
try {
|
|
|
if (this.props.data && prevProps.data && !_.isEqual(this.props.data, prevProps.data)) {
|
|
|
this.setState({contentOffset: {y: 0, x: this._total > 1 ? 2 * (DEVICE_WIDTH-30) : 0}});
|
|
|
this.startAutoScroll('componentDidUpdate');
|
|
|
}
|
|
|
} catch (e) {
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
this.subscription && this.subscription.remove();
|
|
|
this.subscription1 && this.subscription1.remove();
|
|
|
this.stopAutoScroll()
|
|
|
}
|
|
|
|
|
|
startAutoScroll = (fromEvent) => {
|
|
|
let floorData = this.props.floorData.toJS();
|
|
|
let timeout = Number(floorData.speed) && Number(floorData.speed)>500?Number(floorData.speed):2500;
|
|
|
let _data = this.state.data || this.props.data || [];
|
|
|
this.stopAutoScroll()
|
|
|
this.bannerInterval = setInterval(() => {
|
|
|
let interval = DEVICE_WIDTH-30; // WIDTH OF 1 CHILD COMPONENT
|
|
|
|
|
|
let index = this.lastx / interval;
|
|
|
let floor = Math.floor(index);
|
|
|
let decimal = index - floor;
|
|
|
if (decimal < 0.001 || decimal > 0.999) {
|
|
|
index = Math.round(index);
|
|
|
}
|
|
|
let snapTo = this.lastx ? Math.ceil(index) + 1 : 1;
|
|
|
let maxLength = _data.length;
|
|
|
if (snapTo < maxLength && snapTo >= 0) {
|
|
|
this.snapScroll && this.snapScroll.scrollToIndex({index:snapTo, animated: true, viewPosition: 0});
|
|
|
} else {
|
|
|
this.snapScroll && this.snapScroll.scrollToIndex({index:0, animated: true, viewPosition: 0});
|
|
|
}
|
|
|
|
|
|
if (snapTo > 1+this._total) {
|
|
|
this.setState({
|
|
|
currentPage: 0
|
|
|
})
|
|
|
}else {
|
|
|
this.setState({
|
|
|
currentPage: snapTo-2
|
|
|
})
|
|
|
}
|
|
|
|
|
|
}, timeout)
|
|
|
}
|
|
|
|
|
|
stopAutoScroll = () => {
|
|
|
clearInterval(this.bannerInterval)
|
|
|
}
|
|
|
|
|
|
|
|
|
renderItem = (item) => {
|
|
|
let rowData = item.item
|
|
|
return (
|
|
|
<View style={styles.productRow}>
|
|
|
{rowData.map((unit) => {
|
|
|
return (
|
|
|
<SingleFocusProduct
|
|
|
data={unit}
|
|
|
onPressProduct={this.props.onPressProduct}
|
|
|
/>
|
|
|
)
|
|
|
})}
|
|
|
</View>
|
|
|
)
|
|
|
}
|
|
|
|
|
|
|
|
|
_onMomentumScrollEnd = e => {
|
|
|
try {
|
|
|
if (IS_IOS) {
|
|
|
let { x } = e.nativeEvent.contentOffset;
|
|
|
let index = x / (DEVICE_WIDTH-30);
|
|
|
|
|
|
if (Number.isInteger(index) && this._total > 1) {
|
|
|
if (index > 1 + this._total) {
|
|
|
this.stopAutoScroll();
|
|
|
this.snapScroll.scrollToIndex({index:(index - this._total), animated: false, viewPosition: 0});
|
|
|
this.startAutoScroll('_onMomentumScrollEnd');
|
|
|
} else if (index < 2) {
|
|
|
this.stopAutoScroll();
|
|
|
this.snapScroll.scrollToIndex({index:(index + this._total), animated: false, viewPosition: 0});
|
|
|
this.startAutoScroll('_onMomentumScrollEnd');
|
|
|
}
|
|
|
if (!this.state.scrollEnabled) {
|
|
|
this.setState({scrollEnabled: true});
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
} catch (error) {
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
_onLayout = e => {
|
|
|
try {
|
|
|
if (!this.alreadyRendered && this._total > 1) {
|
|
|
this.snapScroll.scrollToIndex({index: 2, animated: false, viewPosition: 0});
|
|
|
this.alreadyRendered = true;
|
|
|
}
|
|
|
this.startAutoScroll('_onLayout');
|
|
|
} catch (error) {
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
render() {
|
|
|
let floorData = this.props.floorData.toJS();
|
|
|
|
|
|
return (
|
|
|
<View style={[this.props.style, styles.container]} >
|
|
|
<View style={styles.headerContainer}>
|
|
|
<Text style={styles.textNormal}>{floorData.title?floorData.title:'推手精选'}</Text>
|
|
|
<View style={styles.indexContainer}>
|
|
|
<Text style={styles.textNormal}>{this.state.currentPage+1}</Text>
|
|
|
<Text style={styles.textSmall}>{'/'+this._total}</Text>
|
|
|
</View>
|
|
|
</View>
|
|
|
|
|
|
<FlatList
|
|
|
ref={(ref)=>{
|
|
|
this.snapScroll = ref;
|
|
|
}}
|
|
|
style={{flex: 1}}
|
|
|
contentOffset={this.state.contentOffset}
|
|
|
onLayout={this._onLayout}
|
|
|
renderItem={this.renderItem}
|
|
|
horizontal={true}
|
|
|
showsHorizontalScrollIndicator={false}
|
|
|
yh_viewVisible={true}
|
|
|
data={this.state.data || this.props.data}
|
|
|
decelerationRate={0}
|
|
|
onScrollBeginDrag = {()=> {
|
|
|
this.isTouching = true;
|
|
|
this.stopAutoScroll()
|
|
|
}}
|
|
|
keyExtractor={(item, index) => '' + index}
|
|
|
scrollEnabled={this.state.scrollEnabled}
|
|
|
onScrollEndDrag = {() => {
|
|
|
this.isTouching = false;
|
|
|
let _data = this.state.data || this.props.data || [];
|
|
|
var interval = DEVICE_WIDTH-30;
|
|
|
|
|
|
var snapTo = (this.scrollingRight)? Math.ceil(this.lastx / interval) :
|
|
|
Math.floor(this.lastx / interval);
|
|
|
let maxLength = _data.length;
|
|
|
if (snapTo < maxLength && snapTo >= 0) {
|
|
|
this.snapScroll.scrollToIndex({index:snapTo, animated: true, viewPosition: 0});
|
|
|
}
|
|
|
|
|
|
if (snapTo > 1 + this._total) {
|
|
|
this.setState({
|
|
|
currentPage: (snapTo - this._total-2)
|
|
|
})
|
|
|
}else if (snapTo < 2) {
|
|
|
this.setState({
|
|
|
currentPage: (snapTo + this._total-2)
|
|
|
})
|
|
|
}else {
|
|
|
this.setState({
|
|
|
currentPage: (snapTo - 2)
|
|
|
})
|
|
|
}
|
|
|
if (snapTo < 1 || snapTo > this._total + 2) {
|
|
|
this.setState({scrollEnabled: false});
|
|
|
}
|
|
|
this.startAutoScroll('onScrollEndDrag');
|
|
|
}}
|
|
|
|
|
|
onScroll={(event)=>{
|
|
|
var nextx = event.nativeEvent.contentOffset.x;
|
|
|
if (!IS_IOS || this.alreadyScrolled) {
|
|
|
this.scrollingRight = (nextx > this.lastx);
|
|
|
this.lastx = nextx;
|
|
|
}
|
|
|
try {
|
|
|
if (!IS_IOS && !this.isTouching) {
|
|
|
let { x } = event.nativeEvent.contentOffset;
|
|
|
let index = x / (DEVICE_WIDTH-30);
|
|
|
let floor = Math.floor(index);
|
|
|
let decimal = index - floor;
|
|
|
if (decimal < 0.001 || decimal > 0.999) {
|
|
|
index = Math.round(index);
|
|
|
}
|
|
|
|
|
|
if (Number.isInteger(index) && this._total > 1) {
|
|
|
if (this.lastIndex == index) return;
|
|
|
this.lastIndex = index;
|
|
|
if (index > 1 + this._total) {
|
|
|
this.stopAutoScroll();
|
|
|
this.snapScroll.scrollToIndex({index:(index-this._total), animated: false, viewPosition: 0});
|
|
|
this.lastx = (DEVICE_WIDTH-30) * (index - this._total);
|
|
|
this.startAutoScroll('onScroll');
|
|
|
} else if (index < 2) {
|
|
|
this.stopAutoScroll();
|
|
|
this.snapScroll.scrollToIndex({index:(index + this._total), animated: false, viewPosition: 0});
|
|
|
this.lastx = (DEVICE_WIDTH-30) * (index + this._total);
|
|
|
this.startAutoScroll('onScroll');
|
|
|
}
|
|
|
if (!this.state.scrollEnabled) {
|
|
|
this.setState({scrollEnabled: true});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (!IS_IOS && (nextx < 5 || nextx > (this._total + 3) * (DEVICE_WIDTH-30) - 5)) {
|
|
|
this.setState({scrollEnabled: false});
|
|
|
this.isTouching = false;
|
|
|
}
|
|
|
if (IS_IOS && !this.alreadyScrolled) {
|
|
|
this.alreadyScrolled = true;
|
|
|
return
|
|
|
}
|
|
|
if (IS_IOS && (nextx < (DEVICE_WIDTH-30) || nextx > (this._total + 2) * (DEVICE_WIDTH-30))) {
|
|
|
this.setState({scrollEnabled: false});
|
|
|
}
|
|
|
} catch (e) {
|
|
|
|
|
|
}
|
|
|
}}
|
|
|
onMomentumScrollEnd={this._onMomentumScrollEnd}
|
|
|
/>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
let {width} = Dimensions.get('window');
|
|
|
const DEVICE_WIDTH_RATIO = width / 375;
|
|
|
|
|
|
let styles = StyleSheet.create({
|
|
|
container: {
|
|
|
width: DEVICE_WIDTH-30,
|
|
|
height: 250*DEVICE_WIDTH_RATIO,
|
|
|
flexDirection: 'column',
|
|
|
marginLeft:15,
|
|
|
marginRight:15,
|
|
|
},
|
|
|
headerContainer: {
|
|
|
height: 40,
|
|
|
flexDirection: 'row',
|
|
|
justifyContent: 'space-between',
|
|
|
alignItems: 'center'
|
|
|
},
|
|
|
indexContainer: {
|
|
|
flexDirection: 'row',
|
|
|
alignItems: 'center'
|
|
|
},
|
|
|
textNormal: {
|
|
|
fontSize: 16,
|
|
|
color: '#222222',
|
|
|
fontFamily: 'PingFang-SC-Medium',
|
|
|
},
|
|
|
textSmall: {
|
|
|
fontSize: 12,
|
|
|
color: '#222222',
|
|
|
fontFamily: 'PingFang-SC-Medium',
|
|
|
},
|
|
|
itemImg : {
|
|
|
width: DEVICE_WIDTH - 40,
|
|
|
height: 210,
|
|
|
marginHorizontal: 5,
|
|
|
overflow: 'hidden',
|
|
|
},
|
|
|
pageControl: {
|
|
|
bottom: 6,
|
|
|
width: DEVICE_WIDTH,
|
|
|
height: 11,
|
|
|
position: 'absolute',
|
|
|
},
|
|
|
productRow:{
|
|
|
width: DEVICE_WIDTH-30,
|
|
|
flexDirection: 'row',
|
|
|
justifyContent: 'space-between',
|
|
|
}
|
|
|
}) |
|
|
\ No newline at end of file |
...
|
...
|
|