Home > Mobile >  React Native Animated: how to detect moment when animated element cross given position
React Native Animated: how to detect moment when animated element cross given position

Time:05-24

How to detect when an animated element has reached a certain position. The element should not stop in this position. It should continue the off-screen animation.

When an element exceeds the given position (line), I have to trigger some action (e.g. change the color of the line to red).

enter image description here

const Component = () => {
  const moveAnimX = useRef(new Animated.Value(0)).current;

  const runAnimation = () => {
    Animated.timing(moveAnimX, {
      toValue: 2000, // out of screen
      duration: 1500, 
      useNativeDriver: true,
    }).start();
  };

  useEffect(() => {
    runAnimation();
  }, []);

  return (
    <Animated.View
      style={[
        {
          height: 50,
          width: 50,
          backgroundColor: 'red',
          transform: [
            {
              translateX: moveAnimX,
            },
          ],
        },
      ]}
    />
  );
};

CodePudding user response:

Since you tagged the question with react-native-reanimated, here's how I would do it using Reanimated 2. You could probably translate this to use the RN Animated API.

  1. Get the line's x coordinate. If you don't set it imperatively, you could measure it with onLayout (shown below), or native methods if you need to know its position on the screen.
  2. Make a shared value that represents the x offset of the square.
  3. Create two animated styles - one for the position of the square, one for the color of the line.
  4. In the animated style for the color of the line, interpolate the x offset so that when the value is below that, it returns one color, and above that, returns another.
  5. Animate.

Pseudocode below

import Animated, {
  interpolateColor,
  useAnimatedStyle,
  useSharedValue,
  withTiming,
} from 'react-native-reanimated';
...

  const [lineX, setLineX] = useState(0);
  const squareOffsetX = useSharedValue(0);
  const animatedSquareStyle = useAnimatedStyle(() => ({
    left: squareOffsetX,
  });
  // the destination offset of the square - substitute whatever makes sense
  const { width: screenWidth } = Dimensions.get('screen');
  
  const animatedLineStyle = useAnimatedStyle(() => ({
    backgroundColor: interpolateColor(
      squareOffsetX.value,
      [0, lineX - 1, lineX, screenWidth],
      ['black', 'black', 'red', 'red']
    ),
  });

  useEffect(() => {
    squareOffsetX.value = withTiming(screenWidth, { duration: 5000 });
  }, []);

  ...
  return (
    <>
      <Animated.View
        style={[styles.line, animatedLineStyle]}
        onLayout={({ nativeEvent }) => setLineX(nativeEvent.layout.x)}
      />
      <Animated.View style={[styles.square, animatedSquareStyle]} />
    </>
  );

CodePudding user response:

It's possible to get current value of Animated.Value by adding addListener to it. The way how to achieve it is explained in this article

Then you can compare it with position of line and trigger action.

  • Related