React Native学习RNReact Native开发

react native 滑动价格区间(step 支持一格移动大

2018-08-23  本文已影响39人  tomorrow_chen
image.png
import React, { Component } from 'react'
import { StyleSheet, View, PanResponder, Text, Dimensions } from 'react-native'

const roundSize = 30  // 圆的大小
const width = Dimensions.get('window').width - roundSize * 1.5 // 设备宽度

/**
 * 价格区间
 */
export default class PriceRange extends Component {
  constructor(props) {
    super(props)
    let scale = width / this.props.range
    let { range, startPrice, endPrice } = this.props
    let start = startPrice === 0 ? roundSize / 2 : scale * startPrice
    let end = endPrice === '不限' ? width : scale * endPrice
    this.state = {
      range,
      startPrice,
      endPrice,
      start, // 起始坐标
      end, // 结束坐标
    }
  }

  componentWillReceiveProps(nextProps) {
    let scale = width / this.props.range
    let { range, startPrice, endPrice } = nextProps
    let start = startPrice === 0 ? roundSize / 2 : (startPrice===range ? width-20 : scale * startPrice)
    let end = endPrice === '不限' ? width : scale * endPrice
    this.setState({
      range,
      startPrice,
      endPrice,
      start, // 起始坐标
      end, // 结束坐标
    })
  }

  componentWillMount() {
    let scale = width / this.props.range
    let step  = this.props.step * scale
    this.panResponderStart = PanResponder.create({
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderGrant: (evt, gestureState) => {
        this.forceUpdate()
      },
      onPanResponderMove: (evt, gestureState) => { // 开始的拖动事件
        let start = gestureState.moveX // 当前拖动所在的坐标
        let threshold = this.state.end - roundSize // 阀值
        if (start >= threshold) {  // 保证开始价格不会超过结束价格
          start = threshold
        }

        start = parseInt(start / step) * step
        let startPrice = Math.floor(start / scale) // 计算开始价格显示值
        if (start <= roundSize) { // 保证开始价格不会小于最小值
          start = roundSize / 2
          startPrice = 0
        }

        this.setState({
          start,
          startPrice
        }, () => {
          this.props.onChange(this.state.startPrice, this.state.endPrice)
        })
      },
      onPanResponderRelease: (evt, gestureState) => true,
      onPanResponderTerminate: (evt, gestureState) => true,
    })
    this.panResponderEnd = PanResponder.create({
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderGrant: (evt, gestureState) => {
        this.forceUpdate()
      },
      onPanResponderMove: (evt, gestureState) => { // 结束的拖动事件
        let end = gestureState.moveX
        let threshold = this.state.start + roundSize // 阀值
        if (end <= threshold) {  // 保证开始价格不会超过结束价格
          end = threshold
        }

        end = parseInt(end / step) * step

        let endPrice = Math.floor(end / scale)
        if (end >= width) { // 保证结束价格不会超过最大值
          end = width
          endPrice = '不限'
        }
        this.setState({
          end,
          endPrice
        }, () => {
          this.props.onChange(this.state.startPrice, this.state.endPrice)
        })
      },
      onPanResponderRelease: (evt, gestureState) => true,
      onPanResponderTerminate: (evt, gestureState) => true,
    })
  }

  render() {
    let { start, end, startPrice, endPrice, range } = this.state
    return (
      <View style={styles.container}>
        <View style={[{ position: 'absolute' }, { left: startPrice===range ? roundSize/2 : start }, { top: -3 }]}><Text style={{color:'#6D7096'}}>{`¥${startPrice}`}</Text></View>
        <View style={[{ position: 'absolute' }, { left: startPrice===range || endPrice===range ? width-20 : end }, { top: -3 }]}><Text style={{color:'#6D7096'}}>{endPrice !== '不限' ? `¥${endPrice}` : (startPrice===range ? `¥${startPrice}+`:endPrice)}</Text></View>
        <View style={{ flexDirection: 'row' }}>
          <View style={[styles.progressContainer, { backgroundColor: '#D6D7E6' }, { width: start }]}></View>
          <View style={[styles.progressContainer, { width: width - start - (width - end) }]}></View>
          <View style={[styles.progressContainer, { backgroundColor: '#D6D7E6' }, { width: width - end }]}></View>
        </View>
        <View style={[styles.circle, { left: start }]} {...this.panResponderStart.panHandlers}>
        </View>
        <View style={[styles.circle, { left: end }]} {...this.panResponderEnd.panHandlers}>
        </View>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    height: 70,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff'
  },
  progressContainer: {
    backgroundColor: '#ffa710',
    height: 4
  },
  circle: {
    position: 'absolute',
    width: roundSize,
    height: roundSize,
    borderRadius: roundSize / 2,
    borderColor: '#D6D7E6',
    borderWidth: 1,
    shadowColor: 'rgba(0,0,0,0.6)',
    shadowRadius: 5,
    shadowOpacity: 0.9,
    backgroundColor: '#f8f8fe'
  }
})

PriceRange.defaultProps = {
  range: 1000, // 价格范围
  startPrice: 0, // 起始价格
  endPrice: '不限', // 结束价格
  step: 50, // 一格大小
  onChange: function() {} // 回调
}

用法

// 回调
onChange(start, end) {
    this.setState({
      start,
      end
    })
}

<PriceRange range={1000} startPrice={this.state.start} endPrice={ this.state.end === 0 ? '不限' : this.state.end } onChange={this.onChange.bind(this)} />
上一篇下一篇

猜你喜欢

热点阅读