etn-ccis / blui-react-native-component-library

Re-usable React-Native components for use in Brightlayer UI applications
BSD 3-Clause "New" or "Revised" License
11 stars 8 forks source link

Enhance support for different scroll containers with CollapsibleHeaderLayout via hooks #537

Open joebochill opened 9 months ago

joebochill commented 9 months ago

Describe the desired feature/functionality

Add support for using the CollapsibleHeader behavior through hooks to be more performant / intuitive.

Additional Context (where / how would this be used)

Applying the necessary props through hooks would simplify the usage and prevent the user from needing to understand the underlying implementation details. The components could be used more declaratively instead of passing everything through props or functions.

Is this request related to a current issue?

Related to previous issue https://github.com/etn-ccis/blui-react-native-component-library/issues/218 where we initially added support for alternative containers.

Suggested implementation details

The proposed implementation would look something like this. I have implemented this on a smaller scale with a simplified Header component (fewer features, fixed sizes for collapsed/expanded) and it worked like a charm. It would need to be expanded to support the additional capabilities/configurability of our Header.

Hook implementation:

export const useCollapsibleHeader = () => {
    const scrollRef = useRef(null);
    const animatedScrollValue = useRef(new Animated.Value(0)).current;
    const contentOffset = { x: 0, y: 0 };

    const handleScroll = Animated.event(
        [
            {
                nativeEvent: {
                    contentOffset: {
                        y: animatedScrollValue,
                    },
                },
            },
        ],
        {
            useNativeDriver: false,
        }
    );

    return {
        scrollProps: {
            ref: scrollRef,
            contentOffset,
            scrollEventThrottle: 32,
            onScroll: handleScroll,
            style: { zIndex: 1 },
            contentContainerStyle: {
                paddingTop: EXPANDED_HEIGHT
            },
        },
        headerProps: {
            scrollPosition: animatedScrollValue,
        },
    };
};

Usage:

const MyScreen = () => {
    const { headerProps, scrollProps } = useCollapsibleHeader();
    return (
        <>
            <Header {...headerProps} {...otherProps}/>
            {/* you can substitute any other container (e.g., SectionList, FlatList, etc.) for ScrollView */}
            <ScrollView {...scrollProps} {...otherProps}>
                {children}
            </ScrollView>
        </>
    );
}