【问题标题】:Translate a View inside an Scrollview in React Native在 React Native 中翻译滚动视图中的视图
【发布时间】:2020-01-07 21:51:05
【问题描述】:

我正在尝试在我的 RN 应用程序中构建这个粘性标题导航栏。基本上,基于 Y 滚动突出显示当前类别的类别的水平滚动视图。

感谢伟大的 William Candillon (https://www.youtube.com/watch?v=xutPT1oZL2M&t=1369s) 的视频,我已经很接近了,但我有一个主要问题。

我在滚动时使用插值来平移视图类别的 X 位置。然后我有一个包裹这个动画视图的滚动视图。问题是 Scrollview 不起作用,因为它没有动画视图位置的参考。正如您在下面的 gif 中看到的(蓝色 -> Animated.View / 红色 -> Scrollview)

我喜欢插值方法,因为它是声明性的并且在本机线程上运行,所以我尽量避免创建附加到 scrollTo() 函数的侦听器。

你会考虑什么方法?

export default ({ y, scrollView, tabs }) => {
  const index = new Value(0);

  const [measurements, setMeasurements] = useState(
    new Array(tabs.length).fill(0)
  );

  const indexTransition = withTransition(index);

  const width = interpolate(indexTransition, {
    inputRange: tabs.map((_, i) => i),
    outputRange: measurements
  });

  const translateX = interpolate(indexTransition, {
    inputRange: tabs.map((_tab, i) => i),
    outputRange: measurements.map((_, i) => {
      return (
        -1 *
          measurements
            .filter((_measurement, j) => j < i)
            .reduce((acc, m) => acc + m, 0) -
        8 * i
      );
    })
  });

  const style = {
    borderRadius: 24,
    backgroundColor: 'black',
    width,
    flex: 1
  };

  const maskElement = <Animated.View {...{ style }} />;

  useCode(
    () =>
      block(
        tabs.map((tab, i) =>
          cond(
            i === tabs.length - 1
              ? greaterOrEq(y, tab.anchor)
              : and(
                  greaterOrEq(y, tab.anchor),
                  lessOrEq(y, tabs[i + 1].anchor)
                ),
            set(index, i)
          )
        )
      ),
    [index, tabs, y]
  );
  return (
    <Animated.View style={[styles.container, {}]}>
      <Animated.ScrollView
        scrollEventThrottle={16}
        horizontal
        style={{ backgroundColor: 'red', flex: 1 }}
      >
        <Animated.View
          style={{
            transform: [{ translateX }],
            backgroundColor: 'blue'
          }}
        >
          <Tabs
            onPress={i => {
              if (scrollView) {
                scrollView.getNode().scrollTo({ y: tabs[i].anchor + 1 });
              }
            }}
            onMeasurement={(i, m) => {
              measurements[i] = m;
              setMeasurements([...measurements]);
            }}
            {...{ tabs, translateX }}
          />
        </Animated.View>
      </Animated.ScrollView>
    </Animated.View>
  );
};

【问题讨论】:

  • ScrollView 工作正常,它确实获得了您的 Animated.View 的位置,只是 Animated.View 之后在视觉上转换了自己的 X 位置。我看不出同时使用 ScrollView 和 Animated.View 的理由。你想让它被用户滚动吗?使用滚动视图。你想通过插值在外面控制它吗?使用 Animated.View
  • 嗯,事情是我想同时拥有它a)按 Y 位置自动滚动和 b)由用户手动滚动以快速概览类别问题是翻译 Animated.View无法手动滚动,因为 Scrollview 没有 Animated.View 的引用
  • “ScrollView 没有 Animated.View 的引用”是什么意思?它不需要引用它,它只是包含它。您可以在 gif 上滚动蓝色元素的事实证明了这一点(否则您根本无法手动滚动它)
  • 是的,我的意思是 Scrollview 包含 Animated.View 但只要不翻译就可以滚动。当我将列表的第一个元素向右平移时(因此它在屏幕中不可见),我无法使用水平 Scrollview 向后滚动,因为它位于 Scrollview 边界的“外部”。有意义吗?
  • 是的,我了解您的问题。并试图指出这是预期的行为 - 在 react native 上,transform: translate 的行为与它在网络上的行为完全相同 - 它只是 视觉上 移动元素。它不影响布局。它不会影响 ScrollView 内的位置。没有其他元素知道 transform: translate 应用于元素。就 ScrollView 而言,在您的 gif 上,它会尽可能滚动到开头。 ScrollView 不关心您的元素在被 ScrollView 定位后,决定将其自身偏移 X 剩余像素数

标签: react-native react-animations


【解决方案1】:

对于遇到此问题的任何人,我通过在动画滚动视图上添加以下内容以自动滚动到活动选项卡来解决它

// Tabs.tsx
 const scrollH = useRef<Animated.ScrollView>(null);
  
 let lastScrollX = new Animated.Value<number>(0);

 //Here's the magic code to scroll to active tab
 //translateX is the animated node value from the position of the active tab
 
  useCode(
    () => block(
      [cond(
        or(greaterThan(translateX, lastScrollX), lessThan(translateX, lastScrollX)),
        call([translateX], (tranX) => {
          if (scrollH.current && tranX[0] !== undefined) {
            scrollH.current.scrollTo({ x: tranX[0], animated: false });
          }
        })),
      set(lastScrollX, translateX)
      ])
    , [translateX]);

// Render the Animated.ScrollView
  return (
    <Animated.ScrollView
      horizontal
      ref={scrollH}
      showsHorizontalScrollIndicator={false}
      >{tabs.map((tab, index) => (
    <Tab ..../> ..... </Animated.ScrollView>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-18
    • 1970-01-01
    相关资源
    最近更新 更多