132 lines
5.2 KiB
JavaScript
132 lines
5.2 KiB
JavaScript
import React, { Component } from 'react';
|
|
import { StyleSheet, View, PanResponder } from 'react-native';
|
|
import { Icon } from '../Icon';
|
|
import styles from './styles';
|
|
import variables from '../../common/styles/variables';
|
|
const rateStyles = StyleSheet.create(styles);
|
|
export class Rate extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.panResponder = null;
|
|
this.containerView = null;
|
|
this.createPanResponder();
|
|
}
|
|
validateProps(props) {
|
|
const { value } = props;
|
|
let tmpValue = value == null ? 0 : value;
|
|
tmpValue = Number(tmpValue);
|
|
if (isNaN(tmpValue)) {
|
|
throw Error('Rate 组件请提供有效的 value 参数');
|
|
}
|
|
const integer = parseInt(tmpValue, 10);
|
|
if (tmpValue - integer !== 0 && tmpValue - integer !== 0.5) {
|
|
throw Error('Rate 组件请提供有效的 value 参数');
|
|
}
|
|
}
|
|
render() {
|
|
this.validateProps(this.props);
|
|
return (React.createElement(View, { ref: c => { this.containerView = c; }, style: [rateStyles.wrapper, this.props.style], collapsable: false },
|
|
React.createElement(View, Object.assign({ collapsable: false, style: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 1 } }, this.panResponder.panHandlers)),
|
|
this.renderIcons(this.props.value)));
|
|
}
|
|
renderIcons(value) {
|
|
const { icons: { half, full, empty }, total, iconSpace, iconSize, iconColor } = this.props;
|
|
const ret = [];
|
|
for (let i = 0; i < total; i++) {
|
|
const marginRight = i === total - 1 ? 0 : iconSpace;
|
|
if (half &&
|
|
value > i &&
|
|
value < i + 1) {
|
|
const tmpProps = { ...half.props, key: i, style: [{ marginRight }, half.props.style] };
|
|
if (half && half.type && half.type.displayName === 'Icon') {
|
|
tmpProps.size = iconSize;
|
|
tmpProps.tintColor = iconColor;
|
|
}
|
|
ret.push(React.cloneElement(half, tmpProps));
|
|
}
|
|
else if (value >= i + 1) {
|
|
const tmpProps = { ...full.props, key: i, style: [{ marginRight }, full.props.style] };
|
|
if (full && full.type && full.type.displayName === 'Icon') {
|
|
tmpProps.size = iconSize;
|
|
tmpProps.tintColor = iconColor;
|
|
}
|
|
ret.push(React.cloneElement(full, tmpProps));
|
|
}
|
|
else {
|
|
const tmpProps = { ...empty.props, key: i, style: [{ marginRight }, empty.props.style] };
|
|
if (empty && empty.type && empty.type.displayName === 'Icon') {
|
|
tmpProps.size = iconSize;
|
|
tmpProps.tintColor = iconColor;
|
|
}
|
|
ret.push(React.cloneElement(empty, tmpProps));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
getValue(pageX) {
|
|
const p = new Promise((resolve) => {
|
|
this.containerView && this.containerView.measure((ox, oy, width, height, px, py) => {
|
|
resolve(px);
|
|
});
|
|
});
|
|
return p.then((containerViewX) => {
|
|
const { iconSize, iconSpace, total, enableHalf } = this.props;
|
|
const locationX = pageX - containerViewX;
|
|
// console.log(pageX, containerViewX)
|
|
if (locationX <= 0) {
|
|
return 0;
|
|
}
|
|
const unitWidth = iconSize + iconSpace;
|
|
let value = Math.floor(locationX / unitWidth);
|
|
if (value >= total) {
|
|
return total;
|
|
}
|
|
const rest = locationX - unitWidth * value;
|
|
if (rest > 0 && rest < (iconSize / 2)) {
|
|
if (!enableHalf) {
|
|
value = value + 1;
|
|
}
|
|
else {
|
|
value = value + 0.5;
|
|
}
|
|
}
|
|
if (rest > (iconSize / 2)) {
|
|
value = value + 1;
|
|
}
|
|
return value;
|
|
});
|
|
}
|
|
handleChange(value) {
|
|
this.props.onChange && this.props.onChange(value);
|
|
}
|
|
createPanResponder() {
|
|
this.panResponder = PanResponder.create({
|
|
onStartShouldSetPanResponder: () => true,
|
|
onPanResponderGrant: (event, gesture) => {
|
|
this.getValue(event.nativeEvent.pageX).then((value) => {
|
|
this.handleChange(value);
|
|
});
|
|
},
|
|
onPanResponderMove: (event, gesture) => {
|
|
this.getValue(event.nativeEvent.pageX).then((value) => {
|
|
this.handleChange(value);
|
|
});
|
|
},
|
|
onPanResponderRelease: event => {
|
|
},
|
|
});
|
|
}
|
|
}
|
|
Rate.defaultProps = {
|
|
total: 5,
|
|
icons: {
|
|
empty: React.createElement(Icon, { source: require(`../../common/images/icons/star-o.png`) }),
|
|
full: React.createElement(Icon, { source: require(`../../common/images/icons/star.png`) }),
|
|
half: React.createElement(Icon, { source: require(`../../common/images/icons/star-half-o.png`) })
|
|
},
|
|
iconSize: 20,
|
|
iconSpace: 4,
|
|
enableHalf: true,
|
|
iconColor: variables.mtdBrandPrimaryDark
|
|
};
|
|
//# sourceMappingURL=index.js.map
|