在缩放后平移 Animated.View,在父视图的边界内

Panning an Animated.View, after being scaled, inside boundaries of parent View

我正在使用 react-native-reanimated and react-native-gesture-handler 创建一个视图,允许您“探索”其中的内容(即使它超出了它的宽度和高度)。

这是我的 gestureHandler 更新 translationX & translationY 变量,后来在 useAnimatedStyle 中用于“移动” <Animated.View>:

const gestureHandler = useAnimatedGestureHandler({
  onStart: (_, ctx) => {
    ctx.startX = translationX.value;
    ctx.startY = translationY.value;
  },
  onActive: (event, ctx) => {
    'worklet';
    translationX.value = ctx.startX + event.translationX;
    translationY.value = ctx.startY + event.translationY;

    // update state to view values on the screen as they change
    runOnJS(setPosition)({ x: translationX.value, y: translationY.value });
  },
  onEnd: () => {
    'worklet';
    const boundedX = clamp(
      translationX.value,
      (BOX_WIDTH - container?.width) * -1,
      0
    );
    const boundedY = clamp(
      translationY.value,
      (BOX_HEIGHT - container?.height) * -1,
      0
    );

    // create "bounce-y" effect when moving the box back inside the bounds
    translationX.value = withTiming(boundedX);
    translationY.value = withTiming(boundedY);

    // update state to view values on the screen as they change
    runOnJS(setPosition)({ x: boundedX, y: boundedY });
  },
});

此代码在以下情况下“有效”:

这是一个 gif (click to view in full size):

我创建了一个示例 Expo Snack 来展示我的问题。如果您将 Transforms.js 中的 INITIAL_SCALE 更改为 0.5 或仅点击粉红色框(它将其比例更改为 NEW_SCALE,请参阅 onPress()),则在边界内平移 no更长的作品。

我发现了问题,它使用原点(中心)缩放框,因此在应用 scale 变换之前,我必须将其转换为“假”,将其原点设置为左上角角落.

{ translateX: -BOX_WIDTH / 2 },
{ translateY: -BOX_HEIGHT / 2 },
{ scale: scale.value }, // <- NOW I am changing the scale of the box
{ translateX: BOX_WIDTH / 2 },
{ translateY: BOX_HEIGHT / 2},

我还制作了一个函数来计算外框的“边缘”,考虑到粉色框的比例:

const getEdges = () => {
  'worklet';
  const pointX =
    (BOX_WIDTH * scale.value - VISIBLE_AREA_WIDTH) * -1;
  const pointY =
    (BOX_HEIGHT * scale.value - VISIBLE_AREA_HEIGHT) * -1;
  return {
    x: {
      min: Math.min(pointX, 0),
      max: Math.max(0, pointX),
    },
    y: {
      min: Math.min(pointY, 0),
      max: Math.max(0, pointY),
    },
  };
};

这是包含这些修复的 working Snack

有用信息: