@lang0909/react-native-alpha-flat-list
Version:
A simple and fully customizable React Native component that implements Alphabetical List
127 lines (106 loc) • 3.31 kB
JavaScript
import React, { useRef } from "react";
import { View, Text, PanResponder } from "react-native";
import PropTypes from "prop-types";
import debounce from "lodash.debounce";
import ResponsiveFontSize from "react-native-responsive-fontsize";
import styles from "./Sidebar.styles";
let containerTop;
let containerHeight;
function Sidebar(props) {
const alphabetContainerRef = useRef();
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponder: () => true,
onPanResponderGrant: debounce(onPanResponderGrant),
onPanResponderMove: debounce(onPanResponderMove),
onPanResponderEnd: debounce(onPanResponderEnd),
})
).current;
function getTouchedLetter(y) {
const top = y - (containerTop || 0);
if (top >= 1 && top <= containerHeight) {
const lettersRanges = props.letters.map((letter, index) => {
return {
letter: letter,
start: (index * containerHeight) / props.letters.length,
end: ((index + 1) * containerHeight) / props.letters.length,
};
});
const index = lettersRanges.findIndex(
(letter) => letter.start <= top && top <= letter.end
);
return props.letters[index];
}
}
function onPanResponderGrant(event, gestureState) {
const letter = getTouchedLetter(gestureState.y0);
onTouchLetter(letter);
}
function onPanResponderMove(event, gestureState) {
const letter = getTouchedLetter(gestureState.moveY);
onTouchLetter(letter);
}
function onPanResponderEnd(event, gestureState) {
props.endFunc();
}
function onTouchLetter(letter) {
props.onScroll(letter);
props.beginFunc();
}
function onLayout() {
if (alphabetContainerRef && alphabetContainerRef.current) {
alphabetContainerRef.current.measure((width, x1, y1, height, px, py) => {
if (!containerTop && !containerHeight) {
containerTop = py;
containerHeight = height;
}
});
}
}
return (
<View
ref={alphabetContainerRef}
{...panResponder.panHandlers}
onLayout={onLayout}
style={[styles.container, props.sidebarContainerStyle]}
>
{props.letters.map((letter) => (
<View
key={letter}
style={[
props.sidebarLetterContainerStyle,
props.activeLetter === letter &&
props.sidebarLetterContainerActiveStyle,
]}
>
<Text
style={[
{
fontSize: ResponsiveFontSize(1.6),
color: "#007afe",
padding: 4,
paddingLeft: 0,
},
props.sidebarLetterStyle,
props.activeLetter === letter && props.sidebarLetterActiveStyle,
]}
>
{letter}
</Text>
</View>
))}
</View>
);
}
Sidebar.propTypes = {
beginFunc: PropTypes.func,
endFunc: PropTypes.func,
onScroll: PropTypes.func,
sidebarContainerStyle: PropTypes.object,
sidebarLetterContainerStyle: PropTypes.object,
sidebarLetterContainerActiveStyle: PropTypes.object,
sidebarLetterStyle: PropTypes.object,
sidebarLetterActiveStyle: PropTypes.object,
};
export default Sidebar;