【问题标题】:React Native - how to scroll a ScrollView to a given location after navigation from another screenReact Native - 从另一个屏幕导航后如何将 ScrollView 滚动到给定位置
【发布时间】:2018-03-22 16:42:27
【问题描述】:

当我们刚刚通过 StackNavigator 导航到当前屏幕时,是否可以告诉 ScrollView 滚动到特定位置?

我有两个屏幕;菜单和项目。菜单是一个按钮列表,每个项目一个。 Items 屏幕包含一个使用 ScrollView 构建的 Carousel,其中包含每个 Item 的图片和详细描述。

当我单击菜单屏幕中的按钮时,我想导航到项目屏幕,并自动滚动到按钮所代表的项目。

我读到您可以在使用 StackNavigator 时像这样传递参数:但我不知道如何在我的项目屏幕中读出该参数。

navigate('Items', { id: '1' })

那么这在 React Native 中是可能的吗?我该怎么做?还是我使用了错误的导航器?

这是我的两个屏幕的简化版本:

App.js:

const SimpleApp = StackNavigator({
    Menu: { screen: MenuScreen},
    Items: { screen: ItemScreen }
  }
);

export default class App extends React.Component {
  render() {
    return <SimpleApp />;
  }
}

菜单.js

export default class Menu extends React.Component {
    constructor(props){
        super(props)
        this.seeDetail = this.seeDetail.bind(this)
    }

    seeDetail(){
        const { navigate } = this.props.navigation;
        navigate('Items')
    }

    render(){
        <Button onPress={this.seeDetail} title='1'/>
        <Button onPress={this.seeDetail} title='2'/>
    }
}

Items.js

export default class Items extends React.Component {
  render(){
    let scrollItems = [] //Somecode that generates and array of items
    return (
      <View>
        <View style={styles.scrollViewContainer}>
          <ScrollView 
          horizontal
          pagingEnabled
          ref={(ref) => this.myScroll = ref}>
            {scrollItems}
          </ScrollView>
        </View>
      </View>
    )
  }  
}

P.S 我目前专门针对 Android,但理想情况下可以有一个跨平台的解决方案。

【问题讨论】:

    标签: react-native react-native-android react-navigation react-native-scrollview


    【解决方案1】:

    对于 iOS - 使用 ScrollViewcontentOffset 属性的最佳方式。通过这种方式,它将最初呈现在正确的位置。使用scrollTo 会在第一个渲染之后添加额外的渲染。

    对于 Android - 除了scrollTo,别无选择

    【讨论】:

      【解决方案2】:

      这里是滚动到带有 id 的道具的示例。

      import React, { Component } from 'react';
      import { StyleSheet, Text, View, ScrollView, TouchableOpacity, Dimensions, Alert, findNodeHandle, Image } from 'react-native';
      class MyCustomScrollToElement extends Component {
      
      constructor(props) {
        super(props)
        this.state = {
        }
        this._nodes = new Map();
      }
      componentDidMount() {
        const data = ['First Element', 'Second Element', 'Third Element', 'Fourth Element', 'Fifth Element' ];
        data.filter((el, idx) => {
          if(el===this.props.id){
            this.scrollToElement(idx);
          }
        })
      
      }
      scrollToElement =(indexOf)=>{
        const node = this._nodes.get(indexOf);
        const position = findNodeHandle(node);
        this.myScroll.scrollTo({ x: 0, y: position, animated: true });
      }
      render(){
        const data = ['First Element', 'Second Element', 'Third Element', 'Fourth Element', 'Fifth Element' ];
        return (
        <View style={styles.container}>
          <ScrollView ref={(ref) => this.myScroll = ref} style={[styles.container, {flex:0.9}]} keyboardShouldPersistTaps={'handled'}>
            <View style={styles.container}>
                {data.map((elm, idx) => <View ref={ref => this._nodes.set(idx, ref)} style={{styles.element}}><Text>{elm}</Text></View>)}
            </View>
          </ScrollView>
        </View>
      );
      

      }

      const styles = StyleSheet.create({
      container: {
        flexGrow: 1,
        backgroundColor:"#d7eff9"
      },
      element:{
        width: 200,
        height: 200,
        backgroundColor: 'red'
      }
      });
      export default MyCustomScrollToElement;
      

      【讨论】:

      • 它返回 _nativeTag 属性而不是实际位置。这并不能解决问题。
      【解决方案3】:

      我读到您可以在使用 StackNavigator 时像这样传递参数:但我不知道如何在我的项目屏幕中读出该参数。

      这是通过在您的子组件中访问this.props.navigation.state.params 来实现的。

      我认为在滚动视图引用上调用scrollTo 的最佳时间是它第一次被分配的时候。你已经给了它一个引用并运行了一个回调函数——我只是调整它,让它同时调用scrollTo

      export default class Items extends React.Component {
        render(){
          let scrollItems = [] //Somecode that generates and array of items
          const {id} = this.props.navigation.state.params;
      
          return (
            <View>
              <View style={styles.scrollViewContainer}>
                <ScrollView 
                horizontal
                pagingEnabled
                ref={(ref) => {
                  this.myScroll = ref
                  this.myScroll.scrollTo() // !!
                }>
                  {scrollItems}
                </ScrollView>
              </View>
            </View>
          )
        }  
      }
      

      这就是我使用FlatListsSectionLists(继承自VirtualizedList)而不是ScrollViews 的原因。 VirtualizedList 有一个更直观的scrollToIndex 函数。 ScrollView 的 scrollTo 需要 x 和 y 参数,这意味着您必须计算要滚动到的确切位置 - 将每个滚动项的宽度乘以您正在滚动到的项的索引。如果每个项目都涉及填充,那就更痛苦了。

      【讨论】:

        【解决方案4】:

        是的,这可以通过使用 scrollTo 方法实现 - 请参阅 docs。您可以在componentDidMount 中调用此方法。你只需要一个 ref 来称呼它:this.myScroll.scrollTo(...)。请注意,如果您有一组相同类型的项目,则应改用FlatList

        【讨论】:

        • 但我需要知道选择了哪个项目才能知道滚动到哪里。如何让我的项目屏幕知道在上一个菜单屏幕中选择了哪个项目?
        • 理想情况下,您应该知道所选项目的索引并将其作为道具发送到items screen。那么您可以使用scrollToIndex 方法,前提是您的物品高度相同。
        • 您好,是的,我知道所选项目的索引。我不确定如何通过 StackNavigator 或任何其他导航器将索引作为道具从一个屏幕传递到另一个屏幕
        猜你喜欢
        • 1970-01-01
        • 2022-01-22
        • 1970-01-01
        • 1970-01-01
        • 2017-11-22
        • 2021-01-25
        • 2020-12-23
        • 1970-01-01
        • 2010-11-09
        相关资源
        最近更新 更多