js
import React, {useRef, useState} from 'react';
import {View, Text, SectionList, StyleSheet, PanResponder} from 'react-native';
const ContactList = () => {
const sectionListRef = useRef(null);
const alphabetRefs = useRef({});
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const [currentIndex, setCurrentIndex] = useState('');
const sections = [
{
title: 'A',
data: ['Alice', 'Amy', 'Alice', 'Amy', 'Alice', 'Amy', 'Alice', 'Amy'],
},
{title: 'B', data: ['Bob', 'Bill']},
{title: 'C', data: ['Charlie', 'Chris']},
{title: 'D', data: ['David']},
{
title: 'E',
data: [
'Emma',
'Ella',
'Emma',
'Ella',
'Emma',
'Ella',
'Emma',
'Ella',
'Emma',
'Ella',
'Emma',
'Ella',
],
},
{
title: 'F',
data: [
'Fmma',
'Flla',
'Fmma',
'Flla',
'Fmma',
'Flla',
'Fmma',
'Flla',
'Fmma',
'Flla',
'Fmma',
'Flla',
],
},
{
title: 'G',
data: [
'Gmma',
'Glla',
'Gmma',
'Glla',
'Gmma',
'Glla',
'Emma',
'Glla',
'Gmma',
'Ella',
'Gmma',
'Glla',
],
},
{
title: 'H',
data: [
'Hmma',
'Hlla',
'Hmma',
'Hlla',
'Hmma',
'Hlla',
'Hmma',
'Hlla',
'Hmma',
'Hlla',
'Hmma',
'Hlla',
],
},
{
title: 'I',
data: [
'Imma',
'Illa',
'Imma',
'Illa',
'Imma',
'Illa',
'Imma',
'Illa',
'Imma',
'Illa',
'Imma',
'Illa',
],
},
{
title: 'J',
data: [
'Jmma',
'Jlla',
'Jmma',
'Jlla',
'Jmma',
'Jlla',
'Jmma',
'Jlla',
'Jmma',
'Jlla',
'Jmma',
'Jlla',
],
},
];
const renderItem = ({item}) => (
<View style={styles.contactItem}>
<Text>{item}</Text>
</View>
);
const renderSectionHeader = ({section: {title}}) => (
<Text style={styles.sectionHeader}>{title}</Text>
);
const handlePanResponderMove = (event, gestureState) => {
let currentLetter = '';
for (let letter in alphabetRefs.current) {
if (
gestureState.moveY >= alphabetRefs.current[letter].start &&
gestureState.moveY < alphabetRefs.current[letter].end
) {
currentLetter = letter;
break;
}
}
setCurrentIndex(currentLetter);
handleScrollToSection(currentLetter);
};
const handleScrollToSection = index => {
const sectionIndex = sections.findIndex(section => section.title === index);
if (sectionIndex !== -1 && sectionListRef.current) {
sectionListRef.current.scrollToLocation({
sectionIndex,
itemIndex: 0,
animated: false,
});
}
};
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderMove: handlePanResponderMove,
});
return (
<View style={styles.container}>
{/* Index Navigation */}
<View {...panResponder.panHandlers} style={styles.indexNav}>
{alphabet.map(letter => (
<View
key={letter}
onLayout={event => {
const layout = event.nativeEvent.layout;
alphabetRefs.current[letter] = {
start: layout.y,
end: layout.y + layout.height,
};
}}>
<Text
style={[
styles.indexLetter,
currentIndex === letter && {fontWeight: 'bold'},
]}>
{letter}
</Text>
</View>
))}
</View>
{/* Contact List */}
<SectionList
ref={sectionListRef}
sections={sections}
renderItem={renderItem}
renderSectionHeader={renderSectionHeader}
keyExtractor={(item, index) => item + index}
scrollEnabled={false}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
},
indexNav: {
width: 30,
backgroundColor: '#f0f0f0',
},
indexLetter: {
textAlign: 'center',
marginVertical: 5,
},
contactItem: {
padding: 20,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
},
sectionHeader: {
padding: 10,
backgroundColor: '#eee',
fontWeight: 'bold',
},
});
export default ContactList;
上面代码直接运行的效果图(支持滑动导航,或者自行手动滑动)