将Reanimated v1的数学部分转换为v3。

huangapple go评论52阅读模式
英文:

convert reanimated v1 math to v3

问题

我想使用 Reanimated v3 来使用 Shared Element Transition 功能,但在升级后出现了许多错误,例如:

const animatedTranslateX = multiply(
  cond(
    greaterThan(x, threshold),
    isRTL ? SCREEN_WIDTH - stickyItemWidth : itemWidth - stickyItemWidth,
    isRTL
      ? add(x, SCREEN_WIDTH - itemWidth - separatorSize)
      : sub(x, separatorSize)
  ),
  isRTL ? 1 : -1
);

multiply, cond, greaterThan, add, sub 已经在 v3 中被弃用并完全移除了,我尝试转换到 v3 但没有成功,有人可以给我一些建议或转换教程吗?非常感谢。

英文:

I want to use Reanimated v3 to using Shared Element Transition function, but I got many error after upgrade, eg:

const animatedTranslateX = multiply(
    cond(
      greaterThan(x, threshold),
      isRTL ? SCREEN_WIDTH - stickyItemWidth : itemWidth - stickyItemWidth,
      isRTL
        ? add(x, SCREEN_WIDTH - itemWidth - separatorSize)
        : sub(x, separatorSize)
    ),
    isRTL ? 1 : -1
  );

multiply, cond, greaterThan, add, sub has deprecated and fully removed from v3, I tried to convert to v3 but not working, can someone give me some advices or converting tutorial? THanks so much

答案1

得分: 1

reanimated v3 让这变得非常简单。而不是必须使用数学辅助函数,您将能够使用常规的 JavaScript。

看看您这里有什么。所以 x 正在驱动此动画。

const animatedTranslateX = multiply(
    cond(
      greaterThan(x, threshold),
      isRTL ? SCREEN_WIDTH - stickyItemWidth : itemWidth - stickyItemWidth,
      isRTL
        ? add(x, SCREEN_WIDTH - itemWidth - separatorSize)
        : sub(x, separatorSize)
    ),
    isRTL ? 1 : -1
  );

要迁移此代码,第一步是设置一个共享值。

const x = useSharedValue(0)

然后,您需要某种方法来更改此共享值。例如,设置滚动视图以更新此值。文档将通过示例解释,但要点是,如果您希望所有这些都在 UI 线程上发生,只需要记住在想要更新共享值时使用 x.value =...。这是与旧版本不同的地方,旧版本中的 x 值不太容易访问。您可能需要调用 set(x, 100) 或类似的内容。

const scrollHandler = useAnimatedScrollHandler(
	{
		onScroll: event => x.value = event.contentOffset.x
	}
);

<Animated.ScrollView
	onScroll={scrollHandler}
	scrollEventThrottle={16} // 不要忘记这个
>
	{children}
</Animated.ScrollView>

然后创建一个派生值:

const animatedTranslateX = useDerivedValue(() => {

   let result = 0;

   // 不使用 cond,而是使用普通的 if
   if (x.value > threshold) {
      result = isRTL ? SCREEN_WIDTH - stickyItemWidth : itemWidth - stickyItemWidth;
   } else {
      // 不使用 add 和 sub,而是使用 + 和 -
      result = isRTL 
          ? x.value + SCREEN_WIDTH - itemWidth - separatorSize
          : x.value - separatorSize;
   }

   // 不使用 mul,而是使用 *
   result = result * (isRTL ? 1 : -1);

   return result;
})

这有点笨拙,但我想先进行直译。当然,我们可以清理代码,在这里您可以执行任何旧的 JavaScript。例如,已经乘以了 isRTL。您只需记住,必须使用 x.value 来"取消引用"共享值。

const animatedTranslateX = useDerivedValue(() => {
   if (x.value > threshold) return isRTL ? -SCREEN_W + stickyW : itemW - stickyW;
   else return isRTL ? -x.value - SCREEN_W + itemW + sepSize : x.value - sepSize;
})

之后,您可以在使用此翻译创建一个动画样式:

const animatedStyle = useAnimatedStyle(() => {
   return {
       transform: [
         {translateX: animatedTranslateX.value} // 这里我们也需要取消引用派生的动画值
       ]
   }
})

并像往常一样应用它
<Animated.View style={animatedStyle} />

您还可以直接在 useAnimatedStyle 回调中进行计算,跳过派生值的创建,这是大多数人会做的。一旦您弄清楚了如何创建共享值并使用手势或滚动视图驱动它,您就可以在 useAnimatedStyle 中使用它,并执行普通的数学运算,而不是使用旧的回调函数。

旧方法是配置要在本地端运行的数学函数,例如使用 add()。RN3 有自己的 JS 线程,因此他们使用一个 Babel 插件来提取您编写的 JavaScript 代码(在 useAnimatedStyle 钩子内,查找 "worklets" 以获取更多信息),并在 JS 线程上运行它。因此,您可以在钩子内执行常规的 JavaScript 操作(除了调用其他函数...未标记为 worklets 的函数除外)。

祝您好运。

英文:

so reanimated v3 makes this really easy. Instead of having to use helper functions for maths you will just be able to use regular js.

Let's look at what you have here. So x is driving the animation here.

const animatedTranslateX = multiply(
    cond(
      greaterThan(x, threshold),
      isRTL ? SCREEN_WIDTH - stickyItemWidth : itemWidth - stickyItemWidth,
      isRTL
        ? add(x, SCREEN_WIDTH - itemWidth - separatorSize)
        : sub(x, separatorSize)
    ),
    isRTL ? 1 : -1
  );

To migrate this code, the first step would be to set up a shared value.

const x = useSharedValue(0)

Then you need something to change this shared value. E.g. setup the scrollview to update this value. The docs will explain in with an example, but the gist would be to use the following, if you want it all to happen on the ui thread. All you need to keep in mind is to use the x.value =... when you want to update the shared value. This is new from the old version, where the value of x was not as easily accessible. You would have needed to call set(x, 100) or something like that.

const scrollHandler = useAnimatedScrollHandler(
	{
		onScroll: event =&gt; x.value = event.contentOffset.x
	}
);

&lt;Animated.ScrollView
	onScroll={scrollHandler}
	scrollEventThrottle={16} // don&#39;t forget this
&gt;
	{children}
&lt;/Animated.ScrollView&gt;

Then create a derrived value:

const animatedTranslateX = useDerivedValue(() =&gt; {

   let result = 0;

   // instead of cond we use regular if
   if(x.value &gt; threshold) {
      result = isRTL ? SCREEN_WIDTH - stickyItemWidth : itemWidth - stickyItemWidth,
   } else {
      // instead of add and sub we just use + and -
      result = isRTL 
          ? x.value + SCREEN_WIDTH - itemWidth - separatorSize
          : x.value - separatorSize
   }

   // instead of mul we just *
   result = result * isRTL ? 1 : -1

   return result;
})

This was a bit clunky, but I wanted to the literal translation first. We could clean up the code of course, here you can do any old js. E.g. already multiply isRTL. All you need to keep in mind is that you have to "dereference" the shared values by using the x.value.

const animatedTranslateX = useDerivedValue(() =&gt; {
   if(x.value &gt; threshold) return isRTL ? -SCREEN_W + stickyW : itemW - stickyW
   else return isRTL ? -x.value - SCREEN_W + itemW + sepSize : x.value - sepSize
})

After this you can create a animated style using this translation:

const animatedStyle = useAnimatedStyle(() =&gt; {
   return {
       transform: [
         {translateX: animatedTranslateX.value} // here we also need to dereference the derived animated value
       ]
   }
})

and apply it as usual:
&lt;Animated.View style={animatedStyle} /&gt;

You can also do the calculation directly in the useAnimatedStyle callback and skip the derived value creation, which most people will do. As soon as you figured out how to create a shared value and drive it using a gesture or scroll view you will be able to use it within the useAnimatedStyle and do just regular math instead of using the old callback functions.

The old way was configuring the math function you wanted to to run on native side, e.g. using add(). RN3 has a own JS thread so they use a babel plugin to extract the js code you've written (within the useAnimatedStyle hook, lookup "worklets" if you want to know more) and run that on the JS thread. So you can do regular js things within the hook (except call other functions... which are not marked as worklets that is).

Best of luck.

答案2

得分: 0

我想你正在寻找类似这样的东西

    import Animated, { useAnimatedStyle, withTiming, useSharedValue } from 'react-native-reanimated';
    const animationConfig = {
      duration: 400,
    };

    ...

    // 在组件内部
    const animatedX = useSharedValue(initialXValue);

    // 当你的X值达到阈值时,你可能想要追踪它并调用这个函数
    const startTransition = () => {
      const nextXValue = ... // 一些计算
      animatedX.value = withTiming(nextXValue, animationConfig);
    };

    const animatedContainerStyle = useAnimatedStyle(() => ({
      transform: [{ translateX: animatedX.value }],
    }));
    
    return (
      <Animated.View style={animatedContainerStyle}>
        ...
      </Animated.View>
    );
英文:

I this you are looking for something like that:

import Animated, { useAnimatedStyle, withTiming, useSharedValue } from &#39;react-native-reanimated&#39;;
const animationConfig = {
  duration: 400,
};

...

// and inside component
const animatedX = useSharedValue(initialXValue);

// you probably want to track your X value and call this function when it reaches the threshold
const startTransition = () =&gt; {
  const nextXValue = ... // some calculations
  animatedX.value = withTiming(nextXValue, animationConfig);
};

const animatedContainerStyle = useAnimatedStyle(() =&gt; ({
  transform: [{ translateX: animatedX.value }],
}));

return (
  &lt;Animated.View style={animatedContainerStyle}&gt;
    ...
  &lt;/Animated.View&gt;
);

huangapple
  • 本文由 发表于 2023年5月22日 17:01:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76304531.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定