carouselHorizontal.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import React, { Children } from 'react'
  2. import {
  3. TouchableOpacity,
  4. View,
  5. Dimensions,
  6. Animated,
  7. Easing,
  8. PanResponder,
  9. } from 'react-native'
  10. import PropTypes from 'prop-types'
  11. import CarouselItem from './carouselItem'
  12. export default class CarouselHorizontal extends React.Component {
  13. constructor(props) {
  14. super(props)
  15. this.state = {
  16. translateX: new Animated.Value(0),
  17. fresh: true,
  18. }
  19. this.index = 0
  20. this.scrollOffset = {
  21. startX: 0,
  22. endX: 0,
  23. directionX: 'R',
  24. }
  25. this.panResponder = props.enableScroll
  26. ? PanResponder.create({
  27. onStartShouldSetPanResponder: (evt, gestureState) => {},
  28. onStartShouldSetPanResponderCapture: (evt, gestureState) => {
  29. this.props.hasTouch && this.props.hasTouch(true)
  30. },
  31. onMoveShouldSetResponderCapture: () => true,
  32. onMoveShouldSetPanResponder: (evt, gestureState) => true,
  33. onMoveShouldSetPanResponderCapture: () => true,
  34. onPanResponderGrant: (evt, gestureState) => {
  35. //
  36. // if (this.props.panResponBool) {
  37. // this.props.hasTouch && this.props.hasTouch(true);
  38. // }
  39. this.scrollOffset.startX = evt.nativeEvent.pageX
  40. },
  41. onPanResponderRelease: (evt, gestureState) => {
  42. this.scrollOffset.endX = evt.nativeEvent.pageX
  43. this.directionJudg()
  44. this.index =
  45. this.scrollOffset.directionX == 'R' ? this.index - 2 : this.index
  46. if (this.index <= -2) {
  47. this.index = 0
  48. } else {
  49. this.scrollCarousel(this.props.children.length)
  50. }
  51. //
  52. // if (this.props.panResponBool) {
  53. // this.props.hasTouch && this.props.hasTouch(false);
  54. // }
  55. },
  56. onShouldBlockNativeResponder: (evt, gestureState) => {
  57. this.props.hasTouch && this.props.hasTouch(false)
  58. // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
  59. // 默认返回true。目前暂时只支持android。
  60. return true
  61. },
  62. })
  63. : {
  64. panHandlers: {},
  65. }
  66. }
  67. static propTypes = {
  68. width: PropTypes.number,
  69. imgTouch: PropTypes.func,
  70. activeOpacity: PropTypes.number,
  71. enableScroll: PropTypes.bool,
  72. delayTime: PropTypes.number,
  73. duration: PropTypes.number,
  74. tintColor: PropTypes.string,
  75. progressBar: PropTypes.bool,
  76. panResponBool: PropTypes.bool,
  77. }
  78. static defaultProps = {
  79. width: Dimensions.get('window').width,
  80. activeOpacity: 1,
  81. imgTouch: () => {},
  82. enableScroll: false,
  83. delayTime: 5000,
  84. duration: 300,
  85. tintColor: 'red',
  86. progressBar: true,
  87. panResponBool: false,
  88. touchArrStyle: {
  89. bottom: '20%',
  90. flexDirection: 'row',
  91. },
  92. entertouchItemStyle: {
  93. marginRight: 5,
  94. width: 20,
  95. height: 5,
  96. borderRadius: 5,
  97. },
  98. touchItemStyle: {
  99. backgroundColor: '#FFF',
  100. opacity: 0.5,
  101. marginRight: 5,
  102. width: 5,
  103. height: 5,
  104. borderRadius: 5,
  105. },
  106. }
  107. componentDidMount() {
  108. this.scrollTimer = setInterval(
  109. () => this.scrollCarousel(this.props.children.length),
  110. this.props.delayTime
  111. )
  112. }
  113. //组件将被卸载
  114. componentWillUnmount() {
  115. //重写组件的setState方法,直接返回空
  116. this.setState = (state, callback) => {
  117. return
  118. }
  119. }
  120. directionJudg() {
  121. this.scrollOffset.directionX =
  122. this.scrollOffset.endX - this.scrollOffset.startX > 0 ? 'R' : 'L'
  123. }
  124. scrollCarousel(count, stopTimer) {
  125. let styleWidth = -this.props.width
  126. this.index++
  127. if (this._animated) {
  128. this._animated.stop()
  129. }
  130. this._animated = Animated.timing(this.state.translateX, {
  131. toValue: styleWidth * this.index,
  132. duration: this.props.duration,
  133. Easing: Easing.linear,
  134. }).start(() => {
  135. if (this.index >= count) {
  136. this.index = 0
  137. this.state.translateX.setValue(0)
  138. }
  139. this.setState({ fresh: !this.state.fresh })
  140. })
  141. }
  142. render() {
  143. let touchArr = []
  144. for (let i = 0; i < this.props.children.length; i++) {
  145. if (this.index == i) {
  146. touchArr.push(
  147. <View
  148. key={i}
  149. style={[
  150. this.props.entertouchItemStyle,
  151. { backgroundColor: this.props.tintColor },
  152. ]}
  153. />
  154. )
  155. } else {
  156. touchArr.push(<View key={i} style={[this.props.touchItemStyle]} />)
  157. }
  158. }
  159. return (
  160. <View
  161. style={{
  162. // width: this.props.width * this.props.children.length,
  163. flex: 1,
  164. }}
  165. >
  166. <Animated.View
  167. {...this.panResponder.panHandlers}
  168. style={[
  169. {
  170. width: this.props.width * this.props.children.length,
  171. overflow: 'hidden',
  172. flexDirection: 'row',
  173. justifyContent: 'flex-start',
  174. },
  175. {
  176. transform: [
  177. {
  178. translateX: this.state.translateX,
  179. },
  180. ],
  181. },
  182. ]}
  183. >
  184. {Children.map(this.props.children, (child, index) => (
  185. <CarouselItem
  186. item={child}
  187. index={index}
  188. imgTouch={e => this.props.imgTouch(e)}
  189. activeOpacity={this.props.activeOpacity}
  190. width={this.props.width}
  191. />
  192. ))}
  193. </Animated.View>
  194. {this.props.progressBar ? (
  195. <View
  196. style={[
  197. {
  198. alignSelf: 'center',
  199. },
  200. this.props.touchArrStyle,
  201. ]}
  202. >
  203. {touchArr}
  204. </View>
  205. ) : null}
  206. </View>
  207. )
  208. }
  209. }