UNPKG

react-native-ui-lib

Version:

<p align="center"> <img src="https://user-images.githubusercontent.com/1780255/105469025-56759000-5ca0-11eb-993d-3568c1fd54f4.png" height="250px" style="display:block"/> </p> <p align="center">UI Toolset & Components Library for React Native</p> <p a

151 lines (136 loc) 4.62 kB
import _ from 'lodash'; import React, { useState, useCallback, useEffect, useRef } from 'react'; import { useSharedValue } from 'react-native-reanimated'; import { useScrollTo } from "../../hooks"; export let OffsetType; (function (OffsetType) { OffsetType["CENTER"] = "CENTER"; OffsetType["DYNAMIC"] = "DYNAMIC"; OffsetType["LEFT"] = "LEFT"; OffsetType["RIGHT"] = "RIGHT"; })(OffsetType || (OffsetType = {})); const useScrollToItem = props => { const { scrollViewRef: propsScrollViewRef, itemsCount, selectedIndex, containerWidth, offsetType = OffsetType.CENTER, addOffsetMargin = true, outerSpacing = 0, innerSpacing = 0 } = props; const itemsWidths = useRef(_.times(itemsCount, () => null)); const itemsWidthsAnimated = useSharedValue(_.times(itemsCount, () => 0)); const itemsOffsetsAnimated = useSharedValue(_.times(itemsCount, () => 0)); const currentIndex = useRef(selectedIndex || 0); const [offsets, setOffsets] = useState({ CENTER: [], LEFT: [], RIGHT: [] }); const { scrollViewRef, scrollTo, onContentSizeChange, onLayout } = useScrollTo({ scrollViewRef: propsScrollViewRef }); // TODO: reset? // useEffect(() => { // itemsWidths.current = _.times(itemsCount, () => null); // }, [itemsCount]); // const contentWidth = _.sum(itemsWidths); // TODO: const scrollEnabled = contentWidth.current > containerWidth; const setSnapBreakpoints = useCallback(widths => { if (_.isEmpty(widths)) { return; } const screenCenter = containerWidth / 2; let index = 0; const centeredOffsets = []; let currentCenterOffset = outerSpacing; const leftOffsets = []; leftOffsets.push(outerSpacing - innerSpacing); const rightOffsets = []; rightOffsets.push(-containerWidth + widths[0] + outerSpacing + innerSpacing); while (index < itemsCount) { /* map animated widths and offsets */ itemsWidthsAnimated.value[index] = widths[index]; if (index > 0) { itemsOffsetsAnimated.value[index] = itemsOffsetsAnimated.value[index - 1] + itemsWidthsAnimated.value[index - 1]; } /* calc center, left and right offsets */ centeredOffsets[index] = currentCenterOffset - screenCenter + widths[index] / 2; ++index; currentCenterOffset += widths[index - 1] + innerSpacing; leftOffsets[index] = leftOffsets[index - 1] + widths[index - 1] + innerSpacing; rightOffsets[index] = rightOffsets[index - 1] + widths[index] + innerSpacing; } if (addOffsetMargin) { index = 1; while (index < itemsCount - 1) { leftOffsets[index] -= widths[index - 1]; rightOffsets[index] += widths[index + 1] + innerSpacing; ++index; } } setOffsets({ CENTER: centeredOffsets, LEFT: leftOffsets, RIGHT: rightOffsets }); // default for DYNAMIC is CENTER // trigger value change itemsWidthsAnimated.value = [...itemsWidthsAnimated.value]; itemsOffsetsAnimated.value = [...itemsOffsetsAnimated.value]; }, [itemsCount, outerSpacing, innerSpacing, addOffsetMargin, containerWidth]); const onItemLayout = useCallback((event, index) => { const { width } = event.nativeEvent.layout; itemsWidths.current[index] = width; if (!_.includes(itemsWidths.current, null)) { setSnapBreakpoints(itemsWidths.current); } }, [setSnapBreakpoints]); const focusIndex = useCallback((index, animated = true) => { if (index >= 0 && offsets.CENTER.length > index) { if (offsetType !== OffsetType.DYNAMIC) { scrollTo(offsets[offsetType][index], animated); } else { const movingLeft = index < currentIndex.current; currentIndex.current = index; scrollTo(movingLeft ? offsets[OffsetType.RIGHT][index] : offsets[OffsetType.LEFT][index], animated); } } }, [offsets, offsetType, scrollTo]); useEffect(() => { if (!_.isUndefined(selectedIndex)) { focusIndex(selectedIndex, false); } }, [selectedIndex, focusIndex]); const reset = useCallback(() => { for (let i = 0; i < itemsCount; ++i) { itemsWidths.current[i] = null; itemsWidthsAnimated.value[i] = 0; itemsOffsetsAnimated.value[i] = 0; } setOffsets({ CENTER: [], LEFT: [], RIGHT: [] }); }, [itemsCount]); return { scrollViewRef, onItemLayout, itemsWidthsAnimated, itemsOffsetsAnimated, focusIndex, reset, onContentSizeChange, onLayout }; }; useScrollToItem.offsetType = OffsetType; export default useScrollToItem;