【问题标题】:Animating a single View based on multiple ScrollView(s)基于多个 ScrollView(s) 为单个 View 设置动画
【发布时间】:2018-04-09 08:33:21
【问题描述】:

我正在开发一个应用程序,我试图根据多个ScrollViews 的滚动位置为View 设置动画。

这就是屏幕的样子。

上面的屏幕有2个部分

  • 顶部有一个View 组件
  • 底部有一个TabNavigator 组件

TabNavigator 中的每个选项卡都有一个 ScrollView (在这种情况下有 2 个但可以更多),我想要实现的是在用户向下滚动时折叠 View 并在用户向上滚动。 在一个选项卡上我做得很好,它完全按照我想要的方式工作,但是当我添加第二个选项卡时问题就来了。

问题

当我在 tab1 上滚动一点并移动到 tab2 并尝试滚动时,它会变得生涩。查看 GIF 以了解我想说的内容


更新

在 expo.io 上查看此零食以实时查看问题

snack.expo.io/SytBkdBAW


我尝试了什么

App.js

export default class App extends Component {

  constructor (props) {
    super(props)

    this.state = {
      /* omitted - not related */
      scrollY: new Animated.Value(0)
    }
  }

  render () {

    let translateY = this.state.scrollY.interpolate({
      inputRange: [0, 600],
      outputRange: [0, -290],
      extrapolate: 'clamp'
    });

    let TabsTranslateY = this.state.scrollY.interpolate({
      inputRange: [0, 600],
      outputRange: [0, -290],
      extrapolate: 'clamp'
    });

    return (
      <View style={styles.container}>
        <Animated.View style={{transform: [{translateY: translateY}], overflow: 'hidden'}}>
          <Text style={styles.welcome}>
            Welcome to React Native!!
          </Text>

          <Text style={styles.time}>
            {this.state.hour} : {this.state.minute}
          </Text>

          <TouchableOpacity onPress={() => { /* omitted */ }} style={styles.button}><Text style={styles.buttonText}>Set Time</Text></TouchableOpacity>
        </Animated.View>
        <Animated.View style={{
          flex: 0,
          transform: [{translateY: TabsTranslateY}],
          height: Dimensions.get('window').height
        }}>
          <Tabs removeClippedSubviews={false} screenProps={{animatedScrollY: this.state.scrollY}}/>
        </Animated.View>
      </View>
    )
  }
}

const styles = StyleSheet.create({/* omitted styles*/})

Home.js (Tab1)

/* omitted imports */
export default class Home extends Component {
  /* omitted navigation options */
  constructor (props) {
    super(props)

    this.state = {
      scrollY: this.props.screenProps.animatedScrollY
    }

  }

  render () {
  return (
      <View>
        <Animated.ScrollView onScroll={Animated.event(
          [{nativeEvent: {contentOffset: {y: this.state.scrollY}}}],
          {useNativeDriver: true}
        )} scrollEventThrottle={16}>

          {Array(90).fill().map((v, i) => {
            return <Text key={i}
                         style={{flex: 1, backgroundColor: '#333', padding: 20, marginVertical: 10, color: 'white'}}>Item
              #{i + 1}</Text>
          })}
        </Animated.ScrollView>
      </View>
    )
  }
}

Photos.js (Tab2)

/* omitted imports */
export default class Photos extends Component {
  /* omitted navigation options */
  constructor (props) {
    super(props)

    this.state = {
      PhotosScrollY: this.props.screenProps.animatedScrollY
    }
  }

  render () {
    return (
      <Animated.ScrollView onScroll={Animated.event(
        [{nativeEvent: {contentOffset: {y: this.state.PhotosScrollY}}}],
        {useNativeDriver: true}
      )} scrollEventThrottle={16}>

        <View style={{flex: 1,}}>
          {Array(90).fill().map((v, i) => {
            return <View key={i} style={/* omitted */}>
              <Text style={/* omitted */}>
                Photo #{i + 1}
              </Text>
            </View>
          })}
        </View>

      </Animated.ScrollView>
    )
  }
}

我不知道如何解决这个问题,任何建议和解决方案都非常感谢。

谢谢。

【问题讨论】:

  • 如果直接从 props 中使用而不分配给 state 会怎样?
  • @AlexanderVitanov 你说的是animatedScrollY 对吧? - 不,我不能直接从状态中使用选项卡,因为这仅在 App.js 中可用,即使我认为这不会改变任何东西。
  • @Azeem Hassni,你能添加你的 Tab.js 文件吗?
  • 当然可以在小吃里查看snack.expo.io/SytBkdBAW -> /Tabs/index.js
  • 假设您打开应用程序,在主页选项卡上向下滚动一点,然后切换到项目选项卡。项目列表应该在顶部吗?如果是这样,并且无法向上滚动,您将如何显示标题?

标签: javascript android ios animation react-native


【解决方案1】:

尝试使用Animated.add()

所以你需要App

const tab1ScrollY = new Animated.Value(0)
const tab2ScrollY = new Animated.Value(0)
const scrollY = Animated.add(tab1ScrollY,tab2ScrollY)

scrollY 的偏移量为tab1 scroll + tab2 scroll

【讨论】:

  • 谢谢,这几乎解决了我的问题,除了一件事,在导航到 Tab2 时滚动 Tab1 后,您无法向下滚动,因此标题卡住,除非您移回 Tab1 并滚动。你可以在这里检查这个行为snack.expo.io/rJXwrLQ1G
  • 如果您对我在评论中指定的问题有解决方案。我会接受答案并奖励赏金。
  • @AzeemHassni,你有没有解决你的问题(标题卡住)?
【解决方案2】:

我遇到了这个问题。我试着用这种方式解决它。 (还在优化中……)

<ParentComponent>
    <CollapsibleHeader/>
    <TabNavigator/>
</ParentComponent>

scrollState 位于 Parent Component 中,TabNavigator 内的 tabs 有 scrollView。 我在绑定动画事件后使用回调更新父组件中的状态。

因此,每当您在两个选项卡之间移动时,状态都位于父组件中,并且会从不同的位置进行更新。

也许这对你有帮助。

注意:仍在优化它。

---------编辑--------

父组件:

状态:scrollY: new Animated.Value(0)

componentDidMount(){
    binding event.
}
componentWillUnmount(){
    Unbind event.
}
onScrollEventCaptured(){
  (update parent state and send it to <CollapsibleHeader/>)*
}

标签 1: 这具有本地状态。 (优化这部分) ,scrollY: new Animated.Value(0)

有一个列表视图

ListView 上的 onScroll 函数:

onScroll={Animated.event([{
                        nativeEvent: {
                            contentOffset: {
                                y: this.state.scrollY
                            }
                        }
                    }], {
                        listener: (event) => {
                            AppEvents.fire("topBar", this.state.scrollY);
                        },
                    })}

AppEvents.fire() 是在 Parent 中捕获的事件。 (捕获的事件然后设置状态,然后作为道具传递给实际动画。)*

对于选项卡 2: 与标签1相同。

*两者相同。

仍在为此做优化工作。对我来说,动画在 iOS 开发中有点生涩,但在生产 iOS 应用程序中看起来很棒。 Android 到处都是生涩的词。

【讨论】:

  • 如果我理解正确,这正是我正在做的。可以分享您的代码,以便我可以比较它以找出我缺少的内容。
  • 编辑了我的答案,请您检查一下并告诉它是否有帮助。
  • 您在使用此方法时遇到任何问题,请告诉我?因为我们也在改进它。?
  • 我在实施此解决方案时遇到问题。你能更新一下这个零食snack.expo.io/SytBkdBAW,这样我就可以阅读你的代码并实现它。
【解决方案3】:

我从来没有使用过 react-native,但我可以肯定地说你为什么会遇到这个问题。我使用了调试工具,发现当您单击选项卡时,应用程序每次都会调用这部分代码:

let translateY = this.state.scrollY.interpolate({
      inputRange: [0, 600],
      outputRange: [0, -290],
      extrapolate: 'clamp'
    });

    let TabsTranslateY = this.state.scrollY.interpolate({
      inputRange: [0, 600],
      outputRange: [0, -290],
      extrapolate: 'clamp'
    });

this.state.scrollY = new Animated.Value(0) 一直在哪里。

基本上,这意味着当您单击选项卡并开始滚动时,它将从 0 开始滚动。您需要找到一个解决方案,记住 Animated.Value 的先前状态或更改动画的输入/输出范围。

这里是如何从 App.js 中点击标签的示例:

<Tabs removeClippedSubviews={false} screenProps={{animatedScrollY: this.state.scrollY}}
          onNavigationStateChange={(prevState, currentState,action) => {
            console.log(currentState);
          }}
 />

希望对你有所帮助。

【讨论】:

  • "一直在哪里this.state.scrollY = new Animated.Value(0)。"不,那是初始值。当您开始滚动时,此值会更新。
  • 如果你能在这个小吃snack.expo.io/SytBkdBAW 中实现你的想法并分享更新的链接,那就太好了。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
  • 1970-01-01
  • 2021-07-04
  • 1970-01-01
相关资源
最近更新 更多