Skip to content

Commit

Permalink
Merge pull request #20 from kolking/fix-location-x
Browse files Browse the repository at this point in the history
Fix incorrect `locationX` in PanResponder move callback
  • Loading branch information
kolking authored May 26, 2024
2 parents 59ddcf4 + e28b87b commit 252c0b7
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 13 deletions.
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -541,4 +541,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 8c8a13ce08d644ffa6042bce5860ab19428fe515

COCOAPODS: 1.11.3
COCOAPODS: 1.15.2
23 changes: 11 additions & 12 deletions src/Rating.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import {
Animated,
ImageSourcePropType,
LayoutChangeEvent,
PanResponder,
StyleProp,
StyleSheet,
Expand Down Expand Up @@ -62,7 +61,7 @@ export const Rating = React.memo(
const animatedSymbol = useRef(new Animated.Value(0)).current;
const animatedOverlay = useRef(new Animated.Value(value)).current;
const props = useRef({ value: 0, onMove, onChange });
const layout = useRef({ x: 0, y: 0 });
const offset = useRef(0);

// Update props used in PanResponder to avoid stale values
props.current = { ...props.current, onMove, onChange };
Expand All @@ -75,10 +74,6 @@ export const Rating = React.memo(
}
}, [interactive, animatedSymbol, animatedOverlay, value]);

const handleLayout = useCallback(({ nativeEvent }: LayoutChangeEvent) => {
layout.current = nativeEvent.layout;
}, []);

const setAnimatedValues = (locationX: number) => {
const newValue = clamp(Math.ceil(locationX / width), 0, maxRating);

Expand All @@ -96,16 +91,21 @@ export const Rating = React.memo(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderTerminationRequest: () => false,
onPanResponderGrant: ({ nativeEvent: { locationX } }) => {
// At this point the locationX is reliable even on Android
onPanResponderGrant: ({ nativeEvent: { pageX, locationX } }) => {
// At this point the locationX is accurate, so we can store
// the offset between pageX and locationX in order to derive
// the correct locationX later in onPanResponderMove callback.
offset.current = pageX - locationX;

setInteractive(true);
setAnimatedValues(locationX);
},
onPanResponderMove: ({ nativeEvent: { pageX } }) => {
// On Android the nativeEvent.locationX is not reliable
// when the touch moves over the wrapper element bounds.
// Therefore the correct value has to be calculated:
const locationX = pageX - layout.current.x;
// But the pageX is accurate, therefore the correct value
// can be calculated using previously stored offset:
const locationX = pageX - offset.current;

if (locationX > 0 && props.current.value > 0) {
setAnimatedValues(locationX);
Expand All @@ -131,7 +131,6 @@ export const Rating = React.memo(
{...(!disabled && panResponder.panHandlers)}
style={[style, styles.root, { width: maxWidth }]}
pointerEvents="box-only"
onLayout={handleLayout}
>
{symbols.map(({ baseSource, fillSource }, index) => (
<RatingSymbol
Expand Down

0 comments on commit 252c0b7

Please sign in to comment.