【问题标题】:How can I smoothen Animated marginTop transitions in a ScrollView?如何平滑 ScrollView 中的 Animated marginTop 过渡?
【发布时间】:2017-05-03 18:40:46
【问题描述】:

对于我的项目,我希望实现一个 ScrollView 来显示项目,就好像您正在浏览一盒名片一样。我当前的实现基于Albert Brand's article on Animated ScrollViews(在尝试了许多其他方法之后)。

然而,现在整个事情变得非常紧张。谁能告诉我如何平滑当前的实施?或者,有没有人有提示如何以不同的方式获得这种行为?任何解决方案都应该适用于 iOS 和 Android。

这个 gif 显示了我当前的实现,包括抖动问题。它还应该清楚地说明我所追求的行为: screencapture of the ScrollView in iOS simulator

这是我当前的实现:

import React from 'react'
import {
  Animated,
  Dimensions,
  ScrollView,
  StyleSheet,
  Text,
  View,
  StatusBar,
} from 'react-native'

const SCREEN_HEIGHT = Dimensions.get('window').height

const yOffset = new Animated.Value(0)

const onScroll = Animated.event(
  [{ nativeEvent: { contentOffset: { y: yOffset } } }],
)

function CardView(props: { children?: ReactElement<*> }) {
  return (
    <Animated.ScrollView
      scrollEventThrottle={16}
      onScroll={onScroll}
      pagingEnabled
    >
      {props.children}
    </Animated.ScrollView>
  )
}

function Page(props: { children?: ReactElement<*>, index: 1 }) {
  return (
    <Animated.View style={[style.scrollPage]}>
      {props.children}
    </Animated.View>
  )
}

function Card(props: { text: string, index: number }) {
  return (
    <Animated.View style={[style.card, marginTransform(props.index)]}>
      <Text>
        {props.text}
      </Text>
    </Animated.View>
  )
}

function marginTransform(index: number) {
  return {
    marginTop: yOffset.interpolate({
      inputRange: [
        (index - 1) * SCREEN_HEIGHT,
        index * SCREEN_HEIGHT,
        (index + 1) * SCREEN_HEIGHT,
        (index + 2) * SCREEN_HEIGHT,
        (index + 3) * SCREEN_HEIGHT,
      ],
      outputRange: [
        -40,
        80,
        SCREEN_HEIGHT + 40,
        2 * SCREEN_HEIGHT + 20,
        3 * SCREEN_HEIGHT,
      ],
      extrapolate: 'clamp',
    }),
  }
}

export default function App() {
  return (
    <CardView>
      {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((i) => {
        return(
          <Page key={i}>
            <Card text={`Card ${i}`} index={i}>
            </Card>
          </Page>
        )
      })}
    </CardView>
  )
}

const style = StyleSheet.create({
  scrollPage: {
    height: SCREEN_HEIGHT,
    backgroundColor: 'transparent',
  },
  card: {
    height: SCREEN_HEIGHT,
    alignItems: 'center',
    borderRadius: 4,
    borderWidth: 1,
    backgroundColor: '#F5FCFF',
  }
})

【问题讨论】:

    标签: react-native react-native-scrollview


    【解决方案1】:

    我找到的简短答案:如果您在滚动时弄乱了它的高度,ScrollViews 将永远不会流畅地动画。在旁注中,我确实发现当我设置 scrollEventThrottle={1}

    时性能得到了显着提升

    我最终实施的解决方案是制作自己的组件;在元素列表的顶部呈现 ScrollView。我将这些元素的动画高度值连接到 ScrollView 的滚动 y 偏移量。

    如果有人遇到相同的用例实现问题,请随时使用我的工作:https://github.com/isilher/react-native-card-scroll

    【讨论】:

    • 出于某种原因,在我的情况下,将 scrollEventThrottle 设置为 1..16 会导致卡顿。将其设置为 16 以上(例如 18)使其完全平滑。进一步增加它,慢慢地引入另一种口吃,因为它错过了太多的事件。
    【解决方案2】:

    确保 Debug JS Remote 已禁用。您还应该删除类中的所有 console.log() (例如,如果您出于调试原因记录 yOffset)。这应该会加快速度。

    【讨论】:

    • 谢谢Luca,我试过了,但优化不是这里的问题。我认为抖动的原因是在滚动时更新 marginTop 也会使整个 ScrollView 的呈现混乱。我不知道如何解决这个问题。
    • 尝试更新top(不是marginTop)并将位置设置为'absolute'
    • 这似乎有相同的结果。另一个缺点是 marginTop 和 top offset 都会将 Card 渲染到它的容器之外:Android 将它们切断。恐怕我将不得不寻找一个完全不同的实现。谢谢你的帮助!在旁注中,当我设置 scrollEventThrottle={1} 而不是 16 时,抖动行为变得更加平滑。但对于实际使用来说仍然太不稳定。
    【解决方案3】:

    嘿试试这个useNativeDriver: true 将帮助你摆脱滞后

    onScroll={Animated.event(
       [{ nativeEvent: { contentOffset: { x: xOffset } } }],
       { useNativeDriver: true }
    )}
    

    【讨论】:

      猜你喜欢
      • 2019-12-31
      • 2023-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-09
      • 2013-08-14
      相关资源
      最近更新 更多