2024-03-16 14:11:43 +08:00

272 lines
11 KiB
JavaScript

import React from 'react';
import { View, Text, ScrollView, PixelRatio } from 'react-native';
import variables from '../../common/styles/variables';
import { range } from '../../common/utils';
import scrollpickerStyles from './styles';
export { scrollpickerStyles };
const px = 1 / PixelRatio.get();
const DEFAULT_CONTAINER_HEIGHT = 1;
export class Scrollpicker extends React.Component {
constructor(props) {
super(props);
this.containerRef = null;
this.scrollers = [];
this.targetItemHeight = null;
this.containerHeight = null;
this.containerRef = null;
const data = this.initialize(props);
this.state = {
...data,
targetItemHeight: null,
containerHeight: null
};
this.scrollers = [];
}
initialize(props) {
const data = this.initData(props);
return data;
}
initData(props) {
let { list, proportion, value } = props;
if (!list || !list.length) {
throw TypeError('提供有效的 list 参数');
}
const { offsetCount } = this.props;
const placeholderList = range(offsetCount).map(() => {
return '';
});
list = list.map(scrollItem => {
const tmp = scrollItem.concat();
[].push.apply(tmp, placeholderList);
[].unshift.apply(tmp, placeholderList);
return tmp;
});
const length = list.length;
if (!proportion ||
!proportion.length ||
(proportion && proportion.length && proportion.length !== length)) {
proportion = range(length).map(() => {
return 1;
});
}
if (!value ||
!value.length ||
(value && value.length && value.length !== length)) {
value = range(length).map(() => {
return 0;
});
}
return {
list,
value,
proportion
};
}
componentDidMount() {
this.getUIData(this.containerRef, DEFAULT_CONTAINER_HEIGHT).then((data) => {
const { targetItemHeight } = data;
const containerHeight = this.resizeContainerHeight(targetItemHeight);
this.setState({
containerHeight,
targetItemHeight
}, () => {
this.getUIData(this.containerRef, this.state.containerHeight).then((uiData) => {
const { value } = this.state;
value.forEach((item, index) => {
this.scrollTo(index, item, false);
});
}).catch((e) => {
console.log(e);
});
});
}).catch((e) => {
console.log(e);
});
}
componentWillReceiveProps(nextProps) {
if (nextProps !== this.props) {
const data = this.initialize(nextProps);
this.setState({
...data
}, () => {
setTimeout(() => {
const { value } = this.state;
value.forEach((item, index) => {
this.scrollTo(index, item);
});
});
});
}
}
getUIData(element, accurateHeight, maxCount) {
let count = 0;
maxCount = maxCount == null ? 20 : maxCount;
return new Promise((resolve, reject) => {
let toCheck = null;
let measure = () => {
let ret = null;
element.measure((x, y, width, height, left, top) => {
// console.log(
// `Get container height: ${height}, accurate height: ${accurateHeight} and target item height: ${
// this.targetItemHeight
// } for ${++count}th.`
// )
if (height) {
// 安卓机器获取高度不精确
const needToReset = height % 1 === 0 ? false : true;
let minHeight;
let maxHeight;
if (needToReset) {
minHeight = Math.floor(height);
maxHeight = minHeight + 1;
}
else {
minHeight = maxHeight = height;
}
if ((minHeight === accurateHeight || maxHeight === accurateHeight) &&
this.targetItemHeight) {
ret = {
rect: {
x,
y,
width,
height
},
targetItemHeight: this.targetItemHeight
};
}
}
toCheck(ret);
});
};
toCheck = (ret) => {
if (ret) {
return resolve(ret);
}
else {
if (count < maxCount) {
setTimeout(() => {
measure();
}, 20);
}
else {
return reject('获取元素高度失败!');
}
}
};
measure();
});
}
resizeContainerHeight(targetItemHeight) {
const { offsetCount } = this.props;
const ret = targetItemHeight + 2 * (targetItemHeight * offsetCount);
return ret;
}
locateIndicator(targetItemHeight) {
const styles = scrollpickerStyles;
const { offsetCount } = this.props;
return (React.createElement(View, { style: [styles.indicator], pointerEvents: 'none' },
React.createElement(View, { style: [
styles.indicator,
styles.indicatorMask,
{ bottom: targetItemHeight + offsetCount * targetItemHeight },
{ borderBottomWidth: 1 * px, borderBottomColor: variables.mtdBorderColorDark }
] }),
React.createElement(View, { style: [
styles.indicator,
styles.indicatorMask,
{ top: targetItemHeight + offsetCount * targetItemHeight },
{ borderTopWidth: 1 * px, borderTopColor: variables.mtdBorderColorDark }
] })));
}
scrollTo(scrollIndex, targetItemIndex, animated) {
const { targetItemHeight } = this.state;
// const { offsetCount } = this.props
this.scrollProper(scrollIndex, targetItemHeight * targetItemIndex, animated);
}
onScroll(scrollIndex, scrollHeight) {
const targetItemIndex = this.scrollProper(scrollIndex, scrollHeight);
this.props.onChange && this.props.onChange(scrollIndex, targetItemIndex);
}
scrollProper(scrollIndex, scrollHeight, animated) {
const { targetItemHeight, list } = this.state;
const { offsetCount } = this.props;
const scrollListLength = list[scrollIndex].length;
let newScrollHeight;
const min = 0;
const max = (scrollListLength - 2 * offsetCount - 1) * targetItemHeight;
if (scrollHeight <= min) {
newScrollHeight = min;
}
else if (scrollHeight >= max) {
newScrollHeight = max;
}
else {
const quotient = parseInt(String(scrollHeight / targetItemHeight), 10);
newScrollHeight = quotient * targetItemHeight;
const halfHeight = targetItemHeight / 2;
if (scrollHeight - newScrollHeight > halfHeight) {
newScrollHeight += targetItemHeight;
}
}
this.scrollers[scrollIndex] && this.scrollers[scrollIndex].scrollTo && this.scrollers[scrollIndex].scrollTo({
x: 0,
y: newScrollHeight,
animated: animated === false ? false : true
});
const targetItemIndex = newScrollHeight / targetItemHeight;
return targetItemIndex;
}
render() {
const styles = scrollpickerStyles;
const { list, proportion, containerHeight, targetItemHeight } = this.state;
return (React.createElement(View, { ref: el => {
this.containerRef = el;
}, style: [
styles.container,
this.props.style,
{ height: containerHeight || DEFAULT_CONTAINER_HEIGHT }
] },
containerHeight && this.locateIndicator(targetItemHeight),
list.map((scrollItem, scrollIndex) => {
return (React.createElement(View, { key: scrollIndex, style: [
styles.proportionWrapper,
{ flex: Number(proportion[scrollIndex]) }
] },
React.createElement(ScrollView, { ref: c => {
this.scrollers[scrollIndex] = c;
}, style: styles.scroller, showsVerticalScrollIndicator: false, contentContainerStyle: [styles.scrollerContentContainer], onScrollEndDrag: (e) => {
this.onScroll(scrollIndex, e.nativeEvent.contentOffset.y);
} }, scrollItem.map((item, index) => {
return (React.createElement(View, { key: index, style: [styles.targetItem, { height: targetItemHeight }], onLayout: e => {
if (item &&
this.targetItemHeight == null &&
e.nativeEvent.layout.height) {
this.targetItemHeight = Math.ceil(e.nativeEvent.layout.height);
// console.log(
// 'OnLayout get target item height:',
// this.targetItemHeight
// )
}
} }, this.props.renderItem ? this.props.renderItem(item, index) :
React.createElement(Text, { style: [
styles.targetItemContent
], numberOfLines: 1 }, typeof item === 'object' ? item.label : item)));
}))));
})));
}
}
Scrollpicker.defaultProps = {
style: {},
list: [
['第一列第一项', '第一列第二项', '第一列第三项'],
['第二列第一项', '第二列第二项', '第二列第三项'],
['第三列第一项', '第三列第二项', '第三列第三项']
],
value: [],
proportion: [2, 1, 1],
offsetCount: 2,
onChange: null,
renderItem: null
};
//# sourceMappingURL=index.js.map