There is a requirement to click somewhere to jump to the specifiedsection
Header, I thought it was pretty simple, so I just started, because I knew there was a method in the sectionList that I could use directly:
This will do, but the UI tells me that not only that, it will also change as I slide, so I searched and searched and couldn’t find it, so I started wrapping. I know that there is a way to get the distance of the current component from the top of the screen:
Then IT occurred to me that I would get the distance of the current header from the top of each section header so that I could slide and know when the corresponding header changed. Here is the source code:
//@ts-check
import React, {useCallback, useRef, useState} from 'react';
import {View, SectionList} from 'react-native';
import styles from './styles';
const sectionTops = []; // section the distance from the top
let sectionListTop = 0; // sectionList Distance from the top
/ * * *@typedef {{ * Suspension: (currentIndex: number, jumpToCurrentIndex: (index: number) => void) => React.ReactElement | null, * uniqueSectionKey: string, * distanceTop: number, * suspensionStyle? : import('react-native').ViewStyle * }
* & import('react-native').SectionListProps
* } SuspensionListProps
* @param {SuspensionListProps} param0 props
*/
const SuspensionList = ({
onScroll,
uniqueSectionKey, //This corresponds to the subscript of the section, otherwise there will be problems sections, renderSectionHeader, Suspension,//Suspension component onScrollBeginDrag, distanceTop,//This is the distance between the suspended component and the above component onMomentumScrollEnd, ListHeaderComponent, suspensionStyle,//Floating component styles... props }) = > {
const refs = [];
const sectionListRef = useRef();
const containerRef = useRef();
const [selectedTabIndex, setTabIndex] = useState(0);
const [currentY, setCurrentY] = useState(0);
const onLayout = useCallback(
(sectionIndex) = > {
// When the drawing is complete, record the distance between each head and the toprefs[sectionIndex]? .measure((x, y, width, height, pageX, pageY) = > {
sectionTops[sectionIndex] = pageY;
});
},
[refs],
);
// Save all section components' refs
const getSectionHeaderRef = useCallback(
(sectionIndex, el) = > {
refs[sectionIndex] = el;
},
[refs],
);
const _renderSectionHeader = useCallback(
({section}) = > {
const sectionIndex = section[uniqueSectionKey];
return (
<View
onLayout={()= >onLayout(sectionIndex)} ref={(el) => getSectionHeaderRef(sectionIndex, el)}> {renderSectionHeader? .({section})}</View>
);
},
[getSectionHeaderRef, onLayout, uniqueSectionKey, renderSectionHeader],
);
const _onScroll = useCallback(
(nativeEvent) = > {
const {
nativeEvent: {
contentOffset: {y}, }, } = nativeEvent; setCurrentY(y); onScroll? .(nativeEvent);// @ts-ignore
if(! sectionListRef.current.isSlide) {return;
}
// If it is less than the height above the next distance of the current section, then it is set. If neither is satisfied, it is the last one
for (let i = 1; i < sectionTops.length; i++) {
if (y <= sectionTops[i] - distanceTop) {
setTabIndex(i - 1);
break;
} else {
setTabIndex(sectionTops.length - 1);
}
}
},
[onScroll, distanceTop],
);
const jumpToCurrentIndex = useCallback(
(index) = > {
// @ts-ignoresectionListRef.current? .scrollToLocation({itemIndex: 0.sectionIndex: index,
viewPosition: 0.viewOffset: distanceTop - sectionListTop,
});
setTabIndex(index);
},
[distanceTop],
);
const SuspensionView = useCallback(() = > {
return (
<View style={[styles.suspensionStyle, suspensionStyle]} >{Suspension? .(selectedTabIndex, jumpToCurrentIndex)}</View>
);
}, [Suspension, jumpToCurrentIndex, selectedTabIndex, suspensionStyle]);
const _onScrollBeginDrag = useCallback(
(event) = >{ onScrollBeginDrag? .(event);// @ts-ignore
sectionListRef.current.isSlide = true;
},
[onScrollBeginDrag],
);
const _onMomentumScrollEnd = useCallback(
(event) = >{ onMomentumScrollEnd? .(event);// @ts-ignore
sectionListRef.current.isSlide = false;
},
[onMomentumScrollEnd],
);
const _ListHeaderComponent = useCallback(() = > {
// @ts-ignore
returnListHeaderComponent? .(selectedTabIndex, jumpToCurrentIndex) ||null;
}, [ListHeaderComponent, selectedTabIndex, jumpToCurrentIndex]);
const _onLayout = useCallback(() = > {
// @ts-ignorecontainerRef.current? .measure? . ((x, y, width, height, pageX, pageY) = >{ sectionListTop = pageY; }); } []);return (
<View style={styles.container} onLayout={_onLayout} ref={containerRef}>
{currentY >= distanceTop && SuspensionView()}
<SectionList
sections={sections}
onScroll={_onScroll}
onScrollBeginDrag={_onScrollBeginDrag}
ListHeaderComponent={_ListHeaderComponent}
ref={sectionListRef}
onMomentumScrollEnd={_onMomentumScrollEnd}
renderSectionHeader={_renderSectionHeader}
{. props} / >
</View>
);
};
export default SuspensionList;
Copy the code
Here is the styles.js file:
import {StyleSheet} from 'react-native';
const styles = StyleSheet.create({
container: {flex: 1},
suspensionStyle: {
position: 'absolute'.zIndex: 9.width: '100%',}});export default styles;
Copy the code
That’s how you get the big cover effect.