reactjs - 在平面列表中的 react-native scrollToOffset 中无法正常工作?
问题描述
在平面列表中,当项目数小于 3 时,滚动到偏移量无法正常工作。如果项目数大于或等于 3,则工作正常。
import React, { Component } from 'react'
import { Animated, Dimensions, RefreshControl, StyleSheet, View, TouchableOpacity } from 'react-native'
import { HEADER_HEIGHT } from '.'
import { CustomText, FlatListWrapper, FlatListWrapperProps } from '../../../common-library/components'
import { ScrollValueContext } from './Context'
import { get } from 'lodash'
import { CENTER, colors, dimens, ROW, SPACE_BETWEEN } from '../../../common-library/config'
import { TAB_BAR_HEIGHT } from './CommunityHeaderComponent'
import { IconButtonWrapper } from '../generic'
import { icons } from '../../common'
import { log } from '../../config'
const labels = {
GO_TO_TOP: 'Go to Top'
}
const styles = StyleSheet.create({
contentStyle: {
paddingTop: HEADER_HEIGHT
},
scrollToTopContainer: {
position: 'absolute',
top: TAB_BAR_HEIGHT,
alignItems: 'center',
left: 0,
right: 0,
zIndex: 999
},
buttonsContainer: {
borderColor: colors.DuckBlue,
backgroundColor: colors.DuckBlue,
borderRadius: dimens.size25,
width: 110,
flexDirection: ROW,
justifyContent: SPACE_BETWEEN,
paddingVertical: dimens.size10,
alignItems: CENTER
},
buttonCta: {
paddingLeft: dimens.size15
},
goToTopLabel: {
color: colors.White,
textAlign: CENTER
},
crossIconCta: {
justifyContent: CENTER,
alignItems: CENTER,
paddingRight: dimens.size15
// paddingTop: dimens.size2
}
})
interface State {
shouldRefresh?: boolean
showScrollToTopView?: boolean
dontShowGoToTop?: boolean
}
interface Props extends FlatListWrapperProps {
uniqueKey?: string
getFlatListRef?: (ref) => any
getScrolledPosition?: (contentOffset) => any
onPullToRefresh?: () => any
renderScrollToTopView?: boolean
}
export class StickyScrollableFlatlistComponent extends Component<Props, State> {
flatListRef
scrolledValue
timerRef
state = {
shouldRefresh: false,
showScrollToTopView: false,
dontShowGoToTop: false
}
componentDidUpdate(prevProps) {
const { showScrollToTopView, dontShowGoToTop } = this.state
if ((!prevProps.isFetching && this.props.isFetching) || (prevProps.isFetching && !this.props.isFetching)) {
if ((showScrollToTopView || dontShowGoToTop) && this.props.renderScrollToTopView) {
this.setState({
showScrollToTopView: false,
dontShowGoToTop: false
})
}
setTimeout(() => {
log('setTileout is called', this.scrolledValue > HEADER_HEIGHT, this.scrolledValue)
this.flatListRef.scrollToOffset({
offset: this.scrolledValue > HEADER_HEIGHT ? HEADER_HEIGHT : HEADER_HEIGHT,
animated: false
})
}, 2000)
}
}
onRefresh = () => {
const { onPullToRefresh } = this.props
if (onPullToRefresh) {
this.setState({
shouldRefresh: true
})
onPullToRefresh().then(() => {
this.setState({
shouldRefresh: false
})
})
}
}
showScrollToTopView = () => {
const { showScrollToTopView } = this.state
const DEVICE_HEIGHT = Dimensions.get('window').height
if (this.scrolledValue >= 2 * DEVICE_HEIGHT - HEADER_HEIGHT && !showScrollToTopView) {
this.setState({
showScrollToTopView: true
})
} else if (this.scrolledValue <= DEVICE_HEIGHT - HEADER_HEIGHT && showScrollToTopView) {
this.setState({
showScrollToTopView: false
})
}
}
onClikCrossIcon = () => {
this.setState({
dontShowGoToTop: true,
showScrollToTopView: false
})
}
moveToTop = () => {
this.flatListRef.scrollToOffset({
offset: HEADER_HEIGHT,
animated: true
})
}
renderScrollToTopView = () => {
return (
<View style={styles.scrollToTopContainer}>
<View style={styles.buttonsContainer}>
<TouchableOpacity onPress={this.moveToTop} style={styles.buttonCta} activeOpacity={1}>
<CustomText textStyle={styles.goToTopLabel}>{labels.GO_TO_TOP}</CustomText>
</TouchableOpacity>
<TouchableOpacity onPress={this.onClikCrossIcon} style={styles.crossIconCta} activeOpacity={1}>
<IconButtonWrapper iconImage={icons.CROSSWHITE_ICON} iconHeight={dimens.size10} iconWidth={dimens.size10} />
</TouchableOpacity>
</View>
</View>
)
}
render() {
const { shouldRefresh, showScrollToTopView, dontShowGoToTop } = this.state
const { getFlatListRef, uniqueKey, getScrolledPosition, renderScrollToTopView = false } = this.props
return (
<ScrollValueContext.Consumer>
{(context) => (
<>
{showScrollToTopView && !dontShowGoToTop && renderScrollToTopView && this.renderScrollToTopView()}
<FlatListWrapper
{...this.props}
onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: context.scrollYValue } } }], {
useNativeDriver: true,
listener: ({ nativeEvent }) => {
const yOffsetValue = get(nativeEvent, 'contentOffset.y', 0)
log('Flatlist wrapper on event is called', yOffsetValue)
this.scrolledValue = yOffsetValue
// context.scrollYValue.setValue(this.scrolledValue)
{
renderScrollToTopView && this.showScrollToTopView()
}
if (getScrolledPosition) {
getScrolledPosition(yOffsetValue)
}
}
})}
refreshControl={
<RefreshControl
refreshing={shouldRefresh}
progressViewOffset={HEADER_HEIGHT}
onRefresh={() => {
this.onRefresh()
}}
/>
}
showCustomizedAnimatedFlatList={true}
contentContainerStyle={[styles.contentStyle, this.props.contentContainerStyle]}
scrollEventThrottle={16}
inputRef={(ref) => {
log('inputRefinputRefis called')
if (ref) {
this.flatListRef = ref
if (getFlatListRef) {
getFlatListRef(ref)
}
context.addFlatListRef(this.flatListRef, uniqueKey)
}
}}
onMomentumScrollEnd={({ nativeEvent }) => {
const { contentOffset } = nativeEvent
if (contentOffset.y === 0) {
log('inside onMomentumScrollEnd')
context.flatListRef.forEach((item) => {
if (item.key !== uniqueKey) {
item.value.scrollToOffset({
offset: 0,
animated: false
})
}
})
}
}}
/>
</>
)}
</ScrollValueContext.Consumer>
)
}
}
所以我的代码是这样的。其中 flatlist 包装器只是 flatlist 的包装器。在平面列表中,当项目数小于 3 时,滚动到偏移量无法正常工作。如果项目数大于或等于 3,则工作正常。
解决方案
推荐阅读
- angular - 更改 ngForOf 以从 Behavior Subject 获取 Iterable
- java - org.apache.cxf.jaxrs.client.WebClient 中的 RecieveTimeout 和 SynchronousTimeout 有什么区别?
- node.js - 在 Node.js 中按顺序排列的“n”个 API 调用?
- asp.net - CurrentCulture 和 CurrentUICulture 是否已缓存?
- angular - 无法在离子 3 中获取未定义或空引用的属性“DestinationType”
- node.js - 如何在本地主机上访问磁盘上的图像并通过网站上的 url 访问
- c# - 如何验证具有在 Linq 表达式中传递的特定值的 Moq 方法调用
- javascript - 将 jsp 导航到 servlet 时出现 404
- php - 使用 ajax 请求发送 csrf_token
- spring-boot - Redis 缓存不适用于 atlassian-connect-spring-boot-jpa-starter