右侧字母手指触摸滑动,以及列表手指触摸滑动,通过setNativeProps方法使字母滑动顺畅
import React, {Component} from 'react'
import {
Image,
PanResponder,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from 'react-native'
import {Brands, BrandVo} from './vo/CarBrandVo'
class ChoosePage extends Component<any, any> {
constructor(props) {
super(props)
this.brand()
this.state = {currentNum: 0}
}
private scrollView: ScrollView
/**
* 英文字母表
*/
private englishList: string[] = []
/**
* 每个条目的位置
*/
private itemPageY = []
/**
* 处理数据
*/
private brandList: BrandVo[] = []
private numPageY = []
private itemHeight = 23
private onScroll = false
private textRefs: Map<string, Text> = new Map()
private viewRefs: Map<string, Text> = new Map()
private textInput: TextInput
private panResponder = PanResponder.create({
onStartShouldSetPanResponderCapture: (evt, gestureState) => {
return true
},
onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
return true
},
onStartShouldSetPanResponder: (evt, gestureState) => {
return true
},
onPanResponderStart: (e) => {
this.onScroll = false
this.onPanResponder(e)
},
onPanResponderMove: (e) => {
this.onPanResponder(e)
},
})
onPanResponder(e) {
let currentY = e.nativeEvent.pageY - 130
let length = this.numPageY.length - 1
if (currentY >= this.numPageY[length].end) {
this.scrollView.scrollToEnd()
this.modifyStyle(length)
return
}
if (currentY <= this.numPageY[0].start) {
this.scrollView.scrollTo({y: 0})
this.modifyStyle(0)
return
}
let index = this.numPageY.findIndex((item) => {
return item.start <= currentY && item.end >= currentY
})
if (index == 0) {
this.scrollView.scrollTo({y: 0})
this.modifyStyle(0)
return
}
this.modifyStyle(index)
this.scrollView.scrollTo({y: this.itemPageY[index - 1].height})
}
private modifyStyle(current) {
this.viewRefs.forEach((item, key) => {
let style = {
backgroundColor:
key == this.englishList[current] ? '#FF5F0F' : '#F8F8FA',
}
if (item) {
item.setNativeProps({style})
}
})
this.textRefs.forEach((item, key) => {
let style = {
color: key == this.englishList[current] ? '#fff' : '#666',
}
if (item) {
item.setNativeProps({style})
}
})
this.textInput.setNativeProps({text: this.englishList[current]})
}
brand() {
const {result} = Brands
result.map((item) => {
let itemBrand = this.brandList.find((value) => {
return item.brandInitial === value.brandInitial
})
if (itemBrand) {
itemBrand.brand.push(item)
} else {
this.englishList.push(item.brandInitial)
this.brandList.push({brandInitial: item.brandInitial, brand: [item]})
}
})
this.englishList.map((item, index) => {
this.numPageY.push({
index: index,
start: this.itemHeight * index + 20,
end: this.itemHeight * (index + 1) + 20,
})
})
}
onLayout(event, index) {
this.itemPageY.push({
height: event.nativeEvent.layout.height,
index: index,
})
if (this.itemPageY.length == this.brandList.length) {
this.itemPageY.sort(function (a, b) {
return a.index - b.index
})
this.itemPageY.flatMap((item, index) => {
if (index != 0) {
item.height = item.height + this.itemPageY[index - 1].height
}
})
}
}
renderItem(item: BrandVo, index) {
let brandVo = item
return (
<View
onLayout={(event) => {
this.onLayout(event, index)
}}
style={{marginHorizontal: 8}}>
<Text style={style.item}>{item.brandInitial}</Text>
<View style={style.flatList}>
{item.brand.map((item) => {
return (
<TouchableOpacity
activeOpacity={1}
onPress={() => {
//点击跳转
}}
style={style.carItem}>
<Image
source={{uri: item.brandLogo}}
style={style.icon}></Image>
<Text style={style.carType}>{item.brandName}</Text>
</TouchableOpacity>
)
})}
</View>
</View>
)
}
numItem(item, index) {
return (
<View
style={{
height: this.itemHeight,
width: 16,
justifyContent: 'center',
}}>
<View
ref={(ref) => {
this.viewRefs.set(item, ref)
}}
style={[
{
backgroundColor: 0 == index ? '#ff0000' : '#f4f4f4',
},
style.numItem,
]}>
<Text
ref={(ref) => {
this.textRefs.set(item, ref)
}}
style={{
fontSize: 12,
color: 0 == index ? '#fff' : '#666',
}}>
{item}
</Text>
</View>
</View>
)
}
render() {
const {currentNum} = this.state
return (
<View style={{backgroundColor: '#f2f4f8'}}>
<Text
style={{
height: 40,
textAlign: 'center',
textAlignVertical: 'center',
lineHeight: 40,
marginTop: 40,
}}>
{'标题'}
</Text>
<View>
<ScrollView
ref={(ref) => {
this.scrollView = ref
}}
alwaysBounceVertical={false}
scrollEventThrottle={100}
overScrollMode={'never'}
bounces={false}
contentContainerStyle={{paddingBottom: 200}}
onScrollBeginDrag={() => {
this.onScroll = true
}}
onScroll={(event) => {
if (this.onScroll) {
var contentSize = event.nativeEvent.contentSize.height
var contentOffset = event.nativeEvent.contentOffset.y
var layoutMeasurement =
event.nativeEvent.layoutMeasurement.height
if (contentOffset + layoutMeasurement + 5 >= contentSize) {
this.modifyStyle(this.itemPageY.length - 1)
return
}
let index = this.itemPageY.findIndex((item, index) => {
return item.height > event.nativeEvent.contentOffset.y
})
this.modifyStyle(index)
}
}}>
{this.brandList.map((item, index) => {
return this.renderItem(item, index)
})}
</ScrollView>
<View style={style.topView}>
<TextInput
ref={(ref) => {
this.textInput = ref
}}
editable={false}
style={style.inputItem}>
{this.englishList[currentNum]}
</TextInput>
</View>
</View>
<View
{...this.panResponder.panHandlers}
hitSlop={{left: 10, right: 10}}
style={style.english}>
{this.englishList.map((item, index) => {
return this.numItem(item, index)
})}
</View>
</View>
)
}
}
const style = StyleSheet.create({
english: {
position: 'absolute',
width: 24,
borderRadius: 90,
right: 20,
top: 130,
backgroundColor: '
alignItems: 'center',
paddingTop: 10,
},
item: {
height: 40,
textAlignVertical: 'center',
lineHeight: 40,
marginLeft: 10,
color: '
fontSize: 16,
},
inputItem: {
height: 40,
marginLeft: 10,
color: '
fontSize: 16,
},
flatList: {
borderRadius: 10,
backgroundColor: '
overflow: 'hidden',
paddingLeft: 14,
},
carItem: {
flexDirection: 'row',
height: 40,
alignItems: 'center',
},
icon: {
width: 24,
height: 24,
},
carType: {
fontSize: 14,
color: '
marginLeft: 6,
},
numItem: {
borderRadius: 90,
width: 16,
height: 16,
justifyContent: 'center',
alignItems: 'center',
},
topView: {
position: 'absolute',
backgroundColor: '
height: 40,
width: '100%',
zIndex: 999,
paddingLeft: 8,
},
})
export default ChoosePage