繁体   English   中英

react-native :根据滚动位置更改视图

[英]react-native : change view corresponding to scroll position

我正在使用Animation.view来更改headerheightbackground

我设置我的heightbackground设置是这样的:

const HeaderHeight = this.state.scrollY.interpolate({
      inputRange:[0, Header_Max_Height - Header_Min_Height],
      outputRange:[Header_Max_Height, Header_Min_Height],
      extrapolate:'clamp'
    })

const AnimateHeaderBackgroundColor = this.state.scrollY.interpolate({
        inputRange: [ 0, ( Header_Max_Height - Header_Min_Height )  ],
        outputRange: [ '#009688', '#00BCD4' ],
        extrapolate: 'clamp'
    })

这是我的动画视图。

<Animated.View style={{width:'100%', height: HeaderHeight, backgroundColor:AnimateHeaderBackgroundColor}}></Animated.View>

一切正常。

我的问题是有没有一种方法可以更改视图,例如heightbackgroundcolor

例如,假设我有两种观点:

//view1
<View style={{width:'100%',height:100, backgroundColor:'red'}}>
 <Text>View1</Text>
</View>

//view2
<View style={{width:'100%',height:100, backgroundColor:'blue'}}>
  <Text>View2</Text>
</View>

我希望view1默认显示并在我滚动到屏幕顶部时显示view2 View放在outputRange会使这成为可能吗?

我想如果你想改变视图,在 RN 中没有直接的方法,但是,在你的情况下,我可以想出一个混合使用opacityposition: absoluteinterpolate()的小技巧,这是一个最小的例子可以直接复制粘贴测试一下:

import React, { Component } from 'react';
import { StyleSheet, Animated, View, ScrollView } from 'react-native';

class AnimationExample extends Component {
  constructor(props) {
    super(props)
    this.state = {
      showBlueView: false,
      animatedOpacityValue: new Animated.Value(0),
    }
  }

  handleScroll = (event) => {
    const { animatedOpacityValue, showBlueView } = this.state;
    const scrollPosition = event.nativeEvent.contentOffset.y;

    if (scrollPosition > 100 && !showBlueView) {
      Animated.timing(animatedOpacityValue, {
        toValue: 1,
      }).start(() => this.setState({ showBlueView: true }))
    }

    if (scrollPosition < 100 && showBlueView) {
      Animated.timing(animatedOpacityValue, {
        toValue: 0,
      }).start(() => this.setState({ showBlueView: false }))
    }
  }

  render() {
    const { animatedOpacityValue } = this.state;
    return (
      <ScrollView
        style={styles.scrollView}
        onScroll={this.handleScroll}
        scrollEventThrottle={16}
      >
        <View style={styles.green} />
        <View style={styles.animatedViewsPositioner}>
          <Animated.View
            style={{
              ...styles.red,
              opacity: animatedOpacityValue.interpolate({
                inputRange: [0, 1],
                outputRange: [1, 0],
              }),
            }}
          />
          <Animated.View
            style={{
              ...styles.blue,
              opacity: animatedOpacityValue.interpolate({
                inputRange: [0, 1],
                outputRange: [0, 1],
              }),
            }}
          />
        </View>
      </ScrollView>
    )
  }
}

const styles = StyleSheet.create({
  scrollView: {
    flex: 1,
  },
  green: {
    height: 600,
    width: '100%',
    backgroundColor: 'green',
  },
  red: {
    height: 300,
    width: '100%',
    backgroundColor: 'red',
  },
  blue: {
    position: 'absolute',
    height: 300,
    width: '100%',
    backgroundColor: 'blue',
  },
  animatedViewsPositioner: {
    position: 'relative',
  },
})

在上面的例子中,我第一接入通过施加滚动位置handleScroll功能的scrollView 确保将scrollEventThrottle设置为 16 以确保每秒触发该功能,但要注意由此可能导致的性能问题(如果您关心,可以查看了解更多信息)。

为了实现当用户滚动到某个位置时触发的视图更改(实际上不是,但看起来像那样),我使用一个view来包装红色和蓝色视图,红色的默认为opacity: 1 ,而蓝色的默认opacity: 0的一个,位于红色的顶部。

我通过使用interpolate()它们的opacity动画来隐藏红色视图并显示蓝色视图。 在此帮助下,两个不透明度值都由一个放在状态中的 animationValue animatedOpacityValue控制。 我添加了一个状态showBlueView通过避免不断设置由 onScroll 触发的状态来优化性能。


这是在两个视图上添加touchableOpacities的更新,只需在未使用时隐藏蓝色视图即可实现。

首先,添加一个日志功能:

log = (stringToPrint) => () => {
  console.log(stringToPrint)
}

其次,改变scrollView通过增加两个这样touchableOpacity

<ScrollView
  style={styles.scrollView}
  onScroll={this.handleScroll}
  scrollEventThrottle={16}
>
  <View style={styles.green} />
  <View style={styles.animatedViewsPositioner}>
    <Animated.View
      style={{
        ...styles.red,
        opacity: animatedOpacityValue.interpolate({
          inputRange: [0, 1],
          outputRange: [1, 0],
        }),
      }}
    >
      <TouchableOpacity
        style={{ backgroundColor: 'black', width: 80, height: 30 }}
        onPress={this.log('click on red')}
      />
    </Animated.View>
    {showBlueView && (
      <Animated.View
        style={{
          ...styles.blue,
          opacity: animatedOpacityValue.interpolate({
            inputRange: [0, 1],
            outputRange: [0, 1],
          }),
        }}
      >
        <TouchableOpacity
          style={{ backgroundColor: 'black', width: 80, height: 30 }}
          onPress={this.log('click on blue')}
        />
      </Animated.View>
    )}
  </View>
</ScrollView>

请注意,我添加了showBlueView &&以在不透明度为 0 时隐藏蓝色视图,以便它不会阻止应用于红色视图的任何点击事件(即使蓝色视图被隐藏,它实际上位于红色视图之上opacity: 0 )。

@Andus 对Animated.event回答

我们的想法是获取最新的 scrollY,然后将其包装为视图的不透明度。 蓝色目标的示例输入范围为 0-50,不透明度为 1 到 0。这意味着它会在向下滚动前 50 像素时淡出。

红色的是反向的,输入范围为 0-200,不透明度为 0 到 1。(淡入)

import React, { Component } from 'react';
import { StyleSheet, Animated, View, ScrollView, SafeAreaView } from 'react-native';

export default class AnimationExample extends Component {
  constructor(props) {
    super(props)
    this.state = {
      scrollY: new Animated.Value(0)
    }
  }

  render() {
  const {scrollY} = this.state;
    return (
      <SafeAreaView style={{flex: 1}}>
      <ScrollView
        style={styles.scrollView}
        onScroll={Animated.event(
          [{nativeEvent: {contentOffset: {y: this.state.scrollY}}}]
        )}
        scrollEventThrottle={16}
      >
        <View style={styles.animatedViewsPositioner}>
          <Animated.View
            style={[styles.box, styles.target, {
             opacity: scrollY.interpolate({
                inputRange: [0, 50],
                outputRange: [1, 0],
              }),
            }]}
          />
          <Animated.View
           style={[styles.box, styles.origin, {
             opacity: scrollY.interpolate({
                inputRange: [0, 200],
                outputRange: [0, 1],
              }),
            }]}
          />
        </View>

      </ScrollView>
      </SafeAreaView>
    )
  }
}

const styles = StyleSheet.create({
  scrollView: {
    flex: 1,
  },
  box: {
    height: 1000,
    width: '100%',
    position: 'absolute'
  },
  origin: {
    backgroundColor: 'red',
    zIndex: 1
  },
  target: {
    backgroundColor: 'blue',
    zIndex: 2
  },
  animatedViewsPositioner: {
    position: 'relative',
    backgroundColor: 'pink',
    height: 10000
  },
})

如果您在显示View使用ScrollView ,我相信您可以使用onScroll回调来获取屏幕在ScrollView的位置,并在用户滚动到顶部时动态更改高度和颜色。

<ScrollView onScroll={this.handleScroll} />

并获得职位,

handleScroll: function(event: Object) {
  console.log(event.nativeEvent.contentOffset.y);
},

参考: 在 React Native 中获取 ScrollView 的当前滚动位置

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM