13

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

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

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

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

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

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

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

应用程序.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'/>
    }
}

项目.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>
    )
  }  
}

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

4

4 回答 4

11

我读到您可以在使用 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 参数,这意味着您必须计算要滚动到的确切位置——将每个滚动项的宽度乘以您正在滚动到的项的索引。而且,如果每个项目都涉及填充,那将变得更加痛苦。

于 2017-10-12T00:56:48.733 回答
2

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

于 2017-10-12T00:13:50.757 回答
1

这是滚动到带有 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;
于 2019-10-21T12:57:05.067 回答
0

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

对于 Android - 没有其他选择scrollTo

于 2019-12-16T22:04:51.793 回答