In flatlist scroll to offset is not working properly when the no of items are less than 3. If the no of items are greater or equal to 3 than it is working exactly fine.
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>
)
}
}
So my code is like this. where flatlist wrapper is just the wrapper of flatlist.
In flatlist scroll to offset is not working properly when the no of items are less than 3. If the no of items are greater or equal to 3 than it is working exactly fine.