There is a requirement to click somewhere to jump to the specifiedsectionHeader, 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.