Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
729 views
in Technique[技术] by (71.8m points)

reactjs - In react-native scrollToOffset in flat list is not working properly?

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...