Skip to content

Commit

Permalink
Merge pull request #135 from postmelee/feature/SwipeRating/relativePa…
Browse files Browse the repository at this point in the history
…nGesture

Fix SwipeRating to start at the tapped point + Add jumpValue and onSwipeRating props, tap to rate feature.
  • Loading branch information
sshivananda authored Mar 22, 2021
2 parents 33db14d + 3a756e6 commit 7be217f
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 14 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ Also refer to the [`example`](https://github.com/Monte9/react-native-ratings/tre
| fractions | 2 | number | The number of decimal places for the rating value; must be between 0 and 20 |
| minValue | 0 | number | The minimum value the user can select |
| style | none | style | Exposes style prop to add additonal styling to the container view (optional) |
| onStartRating | none | function | Callback method when the user starts rating |
| jumpValue | 0 | number | The value to jump when rating value changes (if `jumpValue` === 0.5, rating value increases/decreases like 0, 0.5, 1.0, 1.5 ...). Default is 0 (not to jump)|
| onStartRating | none | function(rating: number) | Callback method when the user starts rating. Gives you the start rating value as a whole number |
| onSwipeRating | none | function(rating: number) | Callback method when the user is swiping. Gives you the current rating value as a whole number|
| onFinishRating | none | function(rating: number) | Callback method when the user finishes rating. Gives you the final rating value as a whole number (required) |

## Try it out
Expand Down
50 changes: 38 additions & 12 deletions src/SwipeRating.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PropTypes from 'prop-types';

import {
View, Text, Animated, PanResponder, Image,
StyleSheet, Platform
StyleSheet, Platform, Dimensions
} from 'react-native';

// RATING IMAGES WITH STATIC BACKGROUND COLOR (white)
Expand Down Expand Up @@ -45,26 +45,35 @@ export default class SwipeRating extends Component {
ratingCount: 5,
showReadOnlyText: true,
imageSize: 40,
minValue: 0
minValue: 0,
jumpValue: 0,
};

constructor(props) {
super(props);
const { onStartRating, onFinishRating, fractions } = this.props;
const { onStartRating, onSwipeRating, onFinishRating, fractions } = this.props;
const position = new Animated.ValueXY();

const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderGrant: () => {
if (typeof onStartRating === 'function') {
onStartRating();
onPanResponderGrant: (event, gesture) => {
const newPosition = new Animated.ValueXY();
const tapPositionX = gesture.x0 - this.state.centerX + gesture.dx;
newPosition.setValue({ x: tapPositionX, y: 0 });
if (this.state.isComponentMounted) {
this.setState({ position: newPosition, value: tapPositionX });
const rating = this.getCurrentRating(tapPositionX);
if (typeof onStartRating === 'function') onStartRating(rating);
}
},
onPanResponderMove: (event, gesture) => {
const newPosition = new Animated.ValueXY();
newPosition.setValue({ x: gesture.dx, y: 0 });
const tapPositionX = gesture.x0 - this.state.centerX + gesture.dx;
newPosition.setValue({ x: tapPositionX, y: 0 });
if (this.state.isComponentMounted) {
this.setState({position: newPosition, value: gesture.dx});
this.setState({ position: newPosition, value: tapPositionX });
const rating = this.getCurrentRating(tapPositionX);
if (typeof onSwipeRating === "function") onSwipeRating(rating);
}
},
onPanResponderRelease: event => {
Expand Down Expand Up @@ -103,6 +112,14 @@ export default class SwipeRating extends Component {
}
}

handleLayoutChange() {
this.ratingRef.measure((fx, fy, width, height, px, py) => {
this.setState({
centerX: (px % Dimensions.get("window").width) + width / 2,
});
});
}

getPrimaryViewStyle() {
const { position } = this.state;
const { imageSize, ratingCount, type } = this.props;
Expand Down Expand Up @@ -179,8 +196,17 @@ export default class SwipeRating extends Component {
} else {
currentRating = !fractions ? Math.ceil(startingValue) : +startingValue.toFixed(fractions);
}

return currentRating;
if (
this.props.jumpValue > 0 &&
this.props.jumpValue < this.props.ratingCount
) {
return (
Math.ceil(currentRating * (1 / this.props.jumpValue)) /
(1 / this.props.jumpValue)
);
} else {
return currentRating;
}
}

setCurrentRating(rating) {
Expand Down Expand Up @@ -241,7 +267,7 @@ export default class SwipeRating extends Component {
<View pointerEvents={readonly ? 'none' : 'auto'} style={style}>
{showRating && this.displayCurrentRating()}
<View style={styles.starsWrapper} {...this.state.panResponder.panHandlers}>
<View style={styles.starsInsideWrapper}>
<View style={styles.starsInsideWrapper} onLayout={(e) => {this.handleLayoutChange(e)}} ref={(view) => {this.ratingRef = view;}}>
<Animated.View style={this.getPrimaryViewStyle()} />
<Animated.View style={this.getSecondaryViewStyle()} />
</View>
Expand Down Expand Up @@ -343,4 +369,4 @@ SwipeRating.propTypes = {
startingValue: PropTypes.number,
fractions: fractionsType,
minValue: PropTypes.number
};
};
13 changes: 12 additions & 1 deletion src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,21 @@ export interface RatingProps {
*/
minValue?: number;

/**
* The number to jump per swipe
* Default is 0 (not to jump)
*/
jumpValue?: number;

/**
* Callback method when the user starts rating.
*/
onStartRating?(): void;
onStartRating?( rating: number): void;

/**
* Callback method when the user is swiping.
*/
onSwipeRating?( rating: number): void;

/**
* Callback method when the user finishes rating. Gives you the final rating value as a whole number
Expand Down

0 comments on commit 7be217f

Please sign in to comment.