如何在与 ScrollView 的原生反应中实现滚动间谍?

Dan*_*ash 4 javascript reactjs react-native

我有一个带有不同元素的 ScrollView 组件说:

<ScrollView>

    <Item1/>

    <Item2/>

    <Item3/>

</ScrollView>
Run Code Online (Sandbox Code Playgroud)

我现在有一个选项卡,我需要根据用户在滚动视图中查看的当前部分来突出显示每个选项卡项目。例如,如果用户<Item2/>在滚动视图中查看/滚动到,那么我应该在选项卡中突出显示 item2 图标。

此外,如果用户单击选项卡项目,它应该自动使滚动视图滚动到相应项目的部分。

有没有办法在本机反应中实现这种滚动监视功能?

ben*_*nel 9

要实现所需的行为,您需要结合几件事。

  1. ScrollView有一个方法scrollTo可以让你滚动到所需的内容位置。
  2. 为了能够检测到ScrollView的当前位置,您需要使用onScroll属性。您可以将此属性与 结合使用scrollEventThrottle以获得更好的准确性。
  3. 要获取每个项目在其中的位置,ScrollView您需要onLayout为每个项目实现属性。

下面是一个小示例应用程序,用于展示如何实现上述步骤。

const Item = props => (
  <View
    style={{ minHeight: 500 }}
    onLayout={e => props.onItemLayout(e, props.index)}>
    <Text>{`Item ${props.index}`}</Text>
  </View>
);

export default class App extends Component {
  constructor() {
    super();
    this.state = {
      sections: [1, 2, 3],
      currentSection: 1
    };
  }
  moveToSetion = section => {
    // scroll view to section
    this.scrollView.scrollTo({ x: 0, y: this.state[section], animated: true });
    // set state to current section
    this.setState({ currentSection: section });
  };
  onItemLayout = ({ nativeEvent: { layout: { x, y, width, height } } }, section) => {
    // setting each items position
    this.setState({ [section]: y });
  };
  onScroll = ({ nativeEvent: { contentOffset: { y, x } } }) => {
    let _currentSection;
    // loop sections to calculate which section scrollview is on
    this.state.sections.forEach((section) => {
      // adding 15 to calculate Text's height
      if((y + 15) > this.state[section]) _currentSection = section
    })
    // settint the currentSection to the calculated current section
    this.setState({ currentSection: _currentSection })
  }
  render() {
    return (
      <View style={styles.container}>
        <View style={styles.buttonContainer}>
          {this.state.sections.map(section => (
            <Button
              key={section}
              title={`Section ${section}`}
              color={this.state.currentSection === section ? 'red' : 'blue'}
              onPress={() => this.moveToSetion(section)}
            />
          ))}
        </View>
        <ScrollView
          style={styles.scrollView}
          ref={ref => (this.scrollView = ref)}
          scrollEventThrottle={100}
          onScroll={this.onScroll}>
          {this.state.sections.map(section => (
            <Item
              key={section}
              index={section}
              onItemLayout={this.onItemLayout}
            />
          ))}
        </ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
  },
  buttonContainer: {
    flexDirection: 'row',
    justifyContent: 'center',
    position: 'fixed',
    top: 0,
  },
  scrollView: {
    paddingLeft: 15,
    paddingRight: 15
  }
});
Run Code Online (Sandbox Code Playgroud)