如何在react native中使用平面列表保持滚动位置?

r3i60tvu  于 2022-12-23  发布在  React
关注(0)|答案(6)|浏览(196)

我是新的React Native。我面临的问题,在保持平面列表的位置时,向前导航,然后回到屏幕。
当前行为
向前然后向后导航时,滚动位置丢失。
预期行为
当用户浏览一个很长的商品列表时,用户向下滚动列表并点击某个商品。应用程序会转到下一个显示产品详细信息的页面。如果用户决定向后导航,页面不会滚动到上一个点。

iaqfqrcu

iaqfqrcu1#

尝试在以下状态下处理滚动位置更改:

<FlatList onScroll={this.handleScroll} />

handleScroll方法:

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

然后,您可以在向后导航时使用scrollToOffset(this.state.scrollPosition)
如果你使用React导航,并希望保持导航后的滚动位置,试试这个黑客:

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)
  })
}
fbcarpbf

fbcarpbf2#

我使用react-navigation在FlatList和细节视图之间导航,还使用react-redux跟踪状态。

  • 基本上是监听导航器的更改,并将当前路线的名称保存为redux
  • 在FlatList中选择项目时,请记住所选项的索引
  • 返回到FlatList时,计算该索引的偏移量并滚动

这一切说起来容易做起来难,在我自己的Component中,FlatList中的行是可变的,因此计算偏移量变得复杂,但这里是一个假设行相同的示例
呈现导航器的My 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}
       />
    )
}
4si2a6ki

4si2a6ki3#

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

thigvfpy

thigvfpy4#

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

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

zphenhs45#

对于任何使用功能组件的人来说,这将是有帮助的。
第一步:使用钩子创建一个常量来保持滚动位置,初始值为零。

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

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

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}
/>
44u64gxh

44u64gxh6#

在平面列表集合scrollsToTop={false}中,当你从细节屏幕导航回来时,这将保留位置。我使用的是Expo版本25。

相关问题