繁体   English   中英

在本机反应中返回时如何使用平面列表保持滚动位置?

[英]How to keep scroll position using flatlist when navigating back in react native ?

我是新来的本地人。 向前导航然后返回到该屏幕时,我在保持平面列表的位置时遇到问题。

当前行为
向前导航然后向后导航时,滚动位置会丢失。

预期行为
当浏览大量项目列表时,用户向下滚动列表并单击某个项目。 该应用程序会转到显示产品详细信息的下一页。 如果用户决定向后导航,则页面不会滚动到前一点。

尝试处理更改状态的滚动位置:

<FlatList onScroll={this.handleScroll} />

处理滚动方法:

handleScroll: function(event: Object) {
 this.setState({ scrollPosition: event.nativeEvent.contentOffset.y });
}

然后您可以在返回时使用scrollToOffset(this.state.scrollPosition)

如果您使用 react-navigation 并希望在导航后保持滚动位置,请尝试以下技巧:

componentDidMount() {
  this.props.navigation.addListener('willBlur', () => {
    const offset = this.state.scrollPosition
    // To prevent FlatList scrolls to top automatically,
    // we have to delay scroll to the original position 
    setTimeout(() => {
      this.flatList.scrollToOffset({ offset, animated: false })
    }, 500)
  })
}

我正在使用 react-navigation 在 FlatList 和详细信息视图之间导航。 我也在使用 react-redux 来跟踪状态。 这是我遵循的过程。

  • 基本上监听导航器的变化并将当前路由的名称保存在 redux 中
  • 当您在 FlatList 中选择一个项目时,请记住您选择的项目的索引
  • 当您返回 FlatList 时,计算该索引的偏移量并滚动

这一切说起来容易一点,然后做起来容易一些,在我自己的组件中,我的 FlatList 中的行是可变的,因此计算偏移量很复杂,但这里有一个假设您的行相同的示例

呈现导航器的我的 App 组件

handleNavigationStateChange = (prevState, newState) => {
    this._getCurrentRouteName(newState)
}

_getCurrentRouteName = (navState) => {
    if (navState.hasOwnProperty('index')) {
        this._getCurrentRouteName(navState.routes[navState.index])
    } else {
        // This is my redux action to save route name
        this.props.updateCurrentRoute( navState.routeName )
    }
}

<AppNavigator onNavigationStateChange={this.handleNavigationStateChange} />

我的带有 FlatList 的组件如下所示

// Renders a row for the FlatList with TouchableHighlight to call viewCreation
renderItem = ( row ) => {
    let creation = row.item
    return (
        <CreationCard onPress={this.viewCreation} index={row.index} creation={creation} />
    )
}

viewCreation = ( index ) => {
    // Get the creation
    let currentCreation = this.props.creations[index]
    // Another reducer saves both my item and index that was selected
    this.props.setSelectedIndex(currentCreation, index)
    // Navigate to the details screen
    this.props.navigation.navigate('CreationDetailScreen')
}

// Assuming all rows are 50 height
getItemLayout = (data, index) => {
    return {length: 50, offset: 50 * index, index}
}

// We mapped the 'currentRoute' property to this component so check
// the props when the component receives new ones.
componentWillReceiveProps( nextProps ){
    // If the currentRoute matches the route for this screen
    if( nextProps.currentRoute === 'CreationListScreen' ){
        // If we also know the last index that was selected on this page
        if( this.props.lastCreationIndex ){
            // Calculate the offset for the last index selected
            let y = this.props.lastCreationIndex * 50
            // and finally scroll to the offset
            this._flatList.scrollToOffset({
                offset: y,
                animated: true
            })
        }
    }
}


// IMPORTANT to include getItemLayout
render(){
    return(
    <FlatList
       ref={(fl) => this._flatList = fl}
       data={this.props.creations}
       renderItem={this.renderItem}
       getItemLayout={this.getItemLayout}
       keyExtractor={creation => creation.id}
       />
    )
}

对于任何使用功能组件的人来说,这将是有帮助的。

第 1 步:使用钩子创建一个常量以保持滚动位置的初始值为零。

  const [scrollPosition,setScrollPosition]=React.useState(0)

第 2 步:创建更新滚动位置的方法。 当用户滚动时。

const handleScroll=(event)=>{
  let yOffset=event.nativeEvent.contentOffset.y / heightOfYourListItem;
  setScrollPosition(yOffset)
}

第 3 步:当用户滚动平面列表时调用 handleScroll() 方法。

    <FlatList
            enableEmptySections={true}
            onScroll={(event)=>handleScroll(event)}
            initialScrollIndex={scrollPosition}
            numColumns={2}
            keyExtractor={(item) => item.Id}
            data={Items}
            renderItem={({item}) =>renderListItems(item}
/>

react-navigation 的当前行为实际上是在屏幕之间来回切换时记住滚动位置。 但是,当您从将headerTransparent设置为与您从那里导航的状态不同的设置的屏幕切换时,它确实会重置。

为了避免使用 setState 多次重新渲染,而不是多次调用的 onScroll,您可以使用这两个 props 来涵盖这两种情况。 第一种情况是用户拖动并停止触摸屏幕,第二种情况是用户通过拖动到达该点。 总的来说,您只有 2 次重新渲染,而不是 20-50 次或其他。

onMomentumScrollEnd={e => setScrollPos(e.nativeEvent.contentOffset.y)}
onScrollEndDrag={e => setScrollPos(e.nativeEvent.contentOffset.y)}

在 Flatlist 中设置scrollsToTop={false}这将在您从详细信息屏幕返回时保留位置。 我正在使用 Expo 版本 25。

暂无
暂无

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

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