-
import React, {useState,useEffect,useRef,useCallback,Component,} from 'react';
import {View,Text,Dimensions,StyleSheet,TouchableOpacity,Image,FlatList,ScrollView,} from 'react-native';
import {scale, sc} from 'react-native-size-matters';
import { isIOSDevice } from '../utils/DimensionUtil';
const {width, height} = Dimensions.get('window');
let screenWidth = width;
let itemHeight = sc(42); // item高度
let distanceItem = 2; //选中高亮高度调节,距离顶部item个高度
// let deviceName = global?.AppInfo?.deviceName == 'HUAWEI' || global?.AppInfo?.deviceName == 'HONOR' || global?.AppInfo?.deviceName == 'OPPO' ? true : false;
let deviceName = global?.AppInfo?.deviceName == 'Xiaomi' || global?.AppInfo?.deviceName == 'Redmi' ? true : false;
export default class ScrollPicker extends Component {
/**
*
1. @param {*} pickData 二维数组,每一个子数组为一联[[{a:1},{a:2}],[{a:11},{a:12}],...arr]
2. @param {*} selectedValue 已选下标组合值,index为0时为第一列,index为1时为第二列...,如[2,1]则表示默认选中第一列的第3个值,第二列的第2个值
3. @param {*} onChange(data, index, scrollIndex, selectedValue) 回调函数: [具体值] | 第n列下标 | 当前选择的行数下标 | [第(当前索引下标)列选中的下标,第(当前索引下标)列选中的下标,...]
4. @param {*} confirm(data, index, scrollIndex, selectedValue) 点击确认按钮 回调同上 通过ref触发
5. 6. iot扩展:
7. @param dataType (1-血压 2-心率 3-体重 4-睡眠 5-血糖)
8. @param allPickerDate n年对应的n个月数据 [{"key":"2022年","data":[{"a":"1月"},{"a":"2月"}],"date":["2022-01","2022-02"]},{"key":"2021年","data":[{"a":"12月"}],"date":["2021-12"]}]
*/
constructor(props) {
super(props);
this.state = {
bottomHeight: sc(350), // 底部滚动区域高度
selectedValue: props.selectedValue || [0,0],
pickData: props.pickData || [],
allData: {}
// selectedValue: [2,1],
// pickData: [[{a: 1},{a: 2},{a: 3},{a: 4},{a: 5}],[{a: 11},{a: 12},{a: 13},{a: 14},{a: 15}]]
};
}
componentDidMount = () => {
// deviceName = global?.AppInfo?.deviceName
// deviceName = global?.AppInfo?.deviceName == 'HUAWEI' || global?.AppInfo?.deviceName == 'HONOR' || global?.AppInfo?.deviceName == 'OPPO' ? true : false;
deviceName = global?.AppInfo?.deviceName == 'Xiaomi' || global?.AppInfo?.deviceName == 'Redmi' ? true : false;
console.log('deviceName', global?.AppInfo?.deviceName);
// console.log('111111111111+++++++++++++=====',this.props.pickData)
};
onMomentumScrollBegin = ({nativeEvent}) => {
// console.log("onMomentumScrollBegin", nativeEvent);
};
onMomentumScrollEnd = (index, {nativeEvent}) => {
let {selectedValue} = this.state;
let unitHeight = itemHeight;
let {contentOffset} = nativeEvent;
let offsetY = contentOffset.y;
let scrollIndex = Math.round(offsetY / unitHeight);
selectedValue[index] = scrollIndex;
let state = true;
// this.setState({selectedValue});
this[`refs${index}`]?.scrollTo({
x: 0,
y: unitHeight * scrollIndex,
animated: true,
});
let data = []
this.state.pickData.map((item, i) => {
let svi = selectedValue[i] <= 0 ? 0 : selectedValue[i]
if(item?.[svi]?.a){
data.push(item?.[svi]?.a)
}
else{
//iot 年、月日期动态高亮(若滚动列没有对应下一列的高亮,则置为高亮最后一项。)
if(!this.state.pickData?.[i]){
state = false;
}
else{
if(i == 2 || i == 1){
data.push(item?.[this.state.pickData[i].length-1]?.a);
selectedValue[i] = this.state.pickData[i].length-1;
}
}
}
});
// 解决ios年滚动超出最后一项,报错问题。
if(!state) return;
if(this.props?.dataType && data?.length == 1 && data?.[0].indexOf('月') != -1){
data.unshift(this.state.pickData[0][this.state.pickData[0].length-1]?.a);
// selectedValue = [0,this.state.pickData[1].length-1];
// console.log('-----------data1111',data,selectedValue)
};
let allData = {data, index, scrollIndex, selectedValue}
this.setState({allData})
this.setState({selectedValue});
let pickArr = this.state.pickData;
// 动态渲染数据 index滚动列(0年份、1月份、2日)
if(this.props?.dataType){
/**
* 年、月
* 动态渲染年份对应的月份(例:n年对应1、2、3月的数据,n+n年对应9、10、11、12月的数据)
*/
// if(this.props?.dataType != 2 && index == 0){
if(index == 0){
// console.log('______________________________',JSON.stringify(this.props.allPickerDate))
let month = [];
this.props.allPickerDate.map((item,index)=>{
if(item.key == data[0]){
month = item.data;
}
});
this.setState({
pickData: [pickArr[0],month]
})
this.props?.onChange({data, index, scrollIndex, selectedValue},[pickArr[0],month]);
return;
};
/**
* 年、月、日
*/
// if(this.props?.dataType == 2){
// // 若当前滚动的为日,则不需要更改数据
// if(index == 2){
// this.props?.onChange({data, index, scrollIndex, selectedValue},null);
// // this.props?.onChange({data, index, scrollIndex, selectedValue},pickArr);
// return;
// };
// // 若当前滚动的为年、月,则需要动态更改对应的日期数据。(不同年份不同月份日期数据不同)
// let month = data[1];
// if(month.length <3){
// month = '0' + month
// };
// let dayArr = [];
// let lastDay = new Date(
// data[0].slice(0,4),
// month.slice(0,2),
// 0,
// ).getDate();
// for(var i=1;i<=lastDay; i ++){
// dayArr.push({a: `${i}日`})
// };
// this.setState({
// pickData: [pickArr[0],pickArr[1],dayArr]
// });
// this.props?.onChange({data, index, scrollIndex, selectedValue},[pickArr[0],pickArr[1],dayArr]);
// return;
// }
// dataType != 2 && index != 0 若当前滚动的为月,则不需要更改数据
this.props?.onChange({data, index, scrollIndex, selectedValue},null);
// this.props?.onChange({data, index, scrollIndex, selectedValue},[pickArr[0],pickArr[1]]);
return;
}
else{
this.props.onChange &&
this.props.onChange({data, index, scrollIndex, selectedValue}); //回调函数: [具体值] | 第n列下标 | 当前选择的行数下标 | [第(当前索引下标)列选中的下标,第(当前索引下标)列选中的下标,...]
}
};
onLayout = () => {
let unitHeight = itemHeight;
let {selectedValue} = this.state;
selectedValue?.forEach((item, index) => {
this[`refs${index}`]?.scrollTo({
x: 0,
y: unitHeight * item,
animated: true,
});
});
};
confirm = () => { //点击确认按钮
let {selectedValue} = this.state;
if(JSON.stringify(this.state.allData) === '{}'){ //没有选择任何值,无任何滑动 直接点确定
let data = []
this.state.pickData.map((item, i) => {
data.push(item[selectedValue[i]].a)
})
this.props.confirm &&
this.props.confirm({data, selectedValue: selectedValue})
}else{
this.props.confirm &&
this.props.confirm({...this.state.allData})
}
}
renderSelectColumn = (list, index) => {
let width = screenWidth / this.state.pickData.length - sc(30);
return (
<View style={{height: '100%', width: width, alignItems: 'center'}}>
<ScrollView
ref={node => {
this[`refs${index}`] = node;
}}
bounces={false}
onLayout={this.onLayout}
alwaysBounceHorizontal={false}
showsVerticalScrollIndicator={false}
onMomentumScrollBegin={this.onMomentumScrollBegin}
onScrollEndDrag={isIOSDevice ? this.onMomentumScrollEnd.bind(this, index):null} // ios用此方法监听
onMomentumScrollEnd={isIOSDevice ? null : this.onMomentumScrollEnd.bind(this, index)} // android用此方法监听
>
<View
style={{
height: itemHeight*distanceItem, // 选中高亮高度调节,*n为距离顶部n个item高度
width: width,
// width: sc(Dimensions.get("screen").width/this.state.pickData.length),
justifyContent: 'center',
alignItems: 'center',
}}></View>
{list?.length ?
list?.map((item, index1) => {
return (
<View
key={index1}
style={{
height: itemHeight,
// width: sc(Dimensions.get("screen").width/this.state.pickData.length),
justifyContent: 'center',
alignItems: 'center',
}}>
<Text
style={[
{fontSize: sc(17), color: '#AFAFAF',},
this.state.selectedValue?.[index] == index1
// paddingHorizontal: sc(20),
? {color: this.props?.fontColor || '#24B39B', fontWeight: 'bold',}
: null,
]}>
{item.a}
</Text>
</View>
);
}):null}
<View
style={{
height: isIOSDevice ? sc(this.state.bottomHeight || 0) - (itemHeight*4-sc(40)) : sc(this.state.bottomHeight || 0) - (itemHeight*(deviceName ? 3.8 : 3.2)-sc(20)), // 调节底部最后一个选项顶起起的高度 米系与其他安卓机有点差距
// width: sc(100),
// height: itemHeight*5+sc(25),
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: 'red',
}}></View>
</ScrollView>
</View>
);
};
render() {
return (
<React.Fragment>
<View style={{ position: "absolute", top: itemHeight*(distanceItem+1)+sc(15), width, height: sc(.5), backgroundColor: "#EEEEEE", zIndex: 999 }}></View>
<View style={{ position: "absolute", top: itemHeight*(distanceItem+2)+sc(15), width, height: sc(.5), backgroundColor: "#EEEEEE", zIndex: 999 }}></View>
{/* <View style={{ position: "absolute", top: itemHeight*3+sc(15), width, height: StyleSheet.hairlineWidth, backgroundColor: "#EEEEEE", zIndex: 999 }}></View> */}
<View
onLayout={e => {
e.nativeEvent.layout.height != this.state.bottomHeight &&
this.setState({bottomHeight: e.nativeEvent.layout.height});
}}
style={{
width: screenWidth,
// height: sc(150),
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
}}>
{this.state.pickData?.map((item, index) => {
return <View key={index}>{this.renderSelectColumn(item, index)}</View>
})}
</View>
</React.Fragment>
);
}
}
- 父组件代码
let date = [
[
{
"a": "00时"
},
{
"a": "01时"
},
{
"a": "02时"
},
{
"a": "03时"
},
{
"a": "04时"
},
{
"a": "05时"
},
{
"a": "06时"
},
{
"a": "07时"
},
{
"a": "08时"
},
{
"a": "09时"
},
{
"a": "10时"
},
{
"a": "11时"
},
{
"a": "12时"
},
{
"a": "13时"
},
{
"a": "14时"
},
{
"a": "15时"
},
{
"a": "16时"
},
{
"a": "17时"
},
{
"a": "18时"
},
{
"a": "19时"
},
{
"a": "20时"
},
{
"a": "21时"
},
{
"a": "22时"
},
{
"a": "23时"
}
],
[
{
"a": "00分"
},
{
"a": "30分"
}
]
];
scrollPicker.current?.confirm(); // 触发confirm
//html部分
<ScrollPicker
ref={scrollPicker}
selectedValue={[ 9, 0]} // 默认选中: 9点
pickData={date}
confirm={data => {
console.log('confirm==', data);
}}
/>