基于多个ScrollView

时间:2017-10-27 16:56:29

标签: javascript android ios animation react-native

我正在开发一个应用程序,我正在尝试根据多个View的滚动位置动画ScrollView

这就是屏幕的外观。

Profile Screen

以上屏幕有两部分

  • Top
  • 上的View组件
  • 底部的TabNavigator组件

TabNavigator中的每个标签都有一个ScrollView(在这种情况下有2个但可以更多),我想要实现的是以用户身份折叠View当用户向上滚动时向下滚动并展开它。 在一个标签上,我做得很好,它正是我想要它的工作方式,但是当我添加第二个标签时出现问题。

问题

当我在tab1上滚动一下并移动到tab2并尝试滚动时,它会变得生涩。看GIF了解我想说的是什么

React Native Animation Jerk

更新

在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>
    )
  }
}

我不确定如何克服这个问题,我们非常感谢任何建议和解决方案。

感谢。

3 个答案:

答案 0 :(得分:4)

尝试使用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

的偏移量

答案 1 :(得分:3)

我遇到了这个问题。我试着这样解决它。 (优化它仍然..)

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

scrollState位于Parent Component中,TabNavigator中的选项卡具有scrollView。 我在绑定Animation事件后使用回调更新父组件中的状态。

因此,无论何时在两个选项卡之间移动,状态都位于父组件中,并从另一个位置更新。

可能这可以帮到你。

注意:仍在优化它。

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

父组件:

州: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

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无处不在它的生涩。

答案 2 :(得分:2)

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

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);
          }}
 />

希望它会对你有帮助。