'use strict';
import React, {
StyleSheet,
PropTypes,
View,
Text,
Animated,
Platform,
Dimensions,
PickerIOS
} from 'react-native';
import PickerAndroid from 'react-native-picker-android';
let Picker = Platform.OS === 'ios' ? PickerIOS : PickerAndroid;
let PickerItem = Picker.Item;
let width = Dimensions.get('window').width;
let height = Dimensions.get('window').height;
export default class PickerAny extends React.Component {
static propTypes = {
pickerBtnText: PropTypes.string,
pickerCancelBtnText: PropTypes.string,
pickerBtnStyle: PropTypes.any,
pickerTitle: PropTypes.string,
pickerTitleStyle: PropTypes.any,
pickerToolBarStyle: PropTypes.any,
pickerItemStyle: PropTypes.any,
pickerHeight: PropTypes.number,
showDuration: PropTypes.number,
pickerData: PropTypes.any.isRequired,
selectedValue: PropTypes.any.isRequired,
onPickerDone: PropTypes.func,
onPickerCancel: PropTypes.func,
onValueChange: PropTypes.func
};
static defaultProps = {
pickerBtnText: '完成',
pickerCancelBtnText: '取消',
pickerHeight: 250,
showDuration: 300,
onPickerDone: ()=>{},
onPickerCancel: ()=>{},
onValueChange: ()=>{}
};
constructor(props, context){
super(props, context);
}
componentWillMount(){
this.state = this._getStateFromProps(this.props);
}
componentWillReceiveProps(newProps){
let newState = this._getStateFromProps(newProps);
this.setState(newState);
}
shouldComponentUpdate(nextProps, nextState, context){
if(JSON.stringify(nextState.selectedValue) === JSON.stringify(this.state.selectedValue)){
return false;
}
return true;
}
_getStateFromProps(props){
//the pickedValue must looks like [wheelone's, wheeltwo's, ...]
//this.state.selectedValue may be the result of the first pickerWheel
let pickerBtnText = props.pickerBtnText;
let pickerCancelBtnText = props.pickerCancelBtnText;
let pickerBtnStyle = props.pickerBtnStyle;
let pickerTitle = props.pickerTitle;
let pickerTitleStyle = props.pickerTitleStyle;
let pickerToolBarStyle = props.pickerToolBarStyle;
let pickerItemStyle = props.pickerItemStyle;
let pickerHeight = props.pickerHeight;
let showDuration = props.showDuration;
let pickerData = props.pickerData;
let selectedValue = props.selectedValue;
let onPickerDone = props.onPickerDone;
let onPickerCancel = props.onPickerCancel;
let onValueChange = props.onValueChange;
let pickerStyle = pickerData.constructor === Array ? 'parallel' : 'cascade';
let firstWheelData;
let firstPickedData;
let secondPickedData;
let secondWheelData;
let secondPickedDataIndex;
let thirdWheelData;
let thirdPickedDataIndex;
let cascadeData = {};
let slideAnim = (this.state && this.state.slideAnim ? this.state.slideAnim : new Animated.Value(-props.pickerHeight));
if(pickerStyle === 'parallel'){
//compatible single wheel sence
if(selectedValue.constructor !== Array){
selectedValue = [selectedValue];
}
if(pickerData[0].constructor !== Array){
pickerData = [pickerData];
}
}
else if(pickerStyle === 'cascade'){
//only support three stage
firstWheelData = Object.keys(pickerData);
firstPickedData = props.selectedValue[0];
secondPickedData = props.selectedValue[1];
cascadeData = this._getCascadeData(pickerData, selectedValue, firstPickedData, secondPickedData, true);
}
//save picked data
this.pickedValue = JSON.parse(JSON.stringify(selectedValue));
this.pickerStyle = pickerStyle;
return {
pickerBtnText,
pickerCancelBtnText,
pickerBtnStyle,
pickerTitle,
pickerTitleStyle,
pickerToolBarStyle,
pickerItemStyle,
pickerHeight,
showDuration,
pickerData,
selectedValue,
onPickerDone,
onPickerCancel,
onValueChange,
//list of first wheel data
firstWheelData,
//first wheel selected value
firstPickedData,
slideAnim,
//list of second wheel data and pickedDataIndex
secondWheelData: cascadeData.secondWheelData,
secondPickedDataIndex: cascadeData.secondPickedDataIndex,
//third wheel selected value and pickedDataIndex
thirdWheelData: cascadeData.thirdWheelData,
thirdPickedDataIndex: cascadeData.thirdPickedDataIndex
};
}
_slideUp(){
this.isMoving = true;
Animated.timing(
this.state.slideAnim,
{
toValue: 0,
duration: this.state.showDuration,
}
).start((evt) => {
if(evt.finished) {
this.isMoving = false;
this.isPickerShow = true;
}
});
}
_slideDown(){
this.isMoving = true;
Animated.timing(
this.state.slideAnim,
{
toValue: -this.state.pickerHeight,
duration: this.state.showDuration,
}
).start((evt) => {
if(evt.finished) {
this.isMoving = false;
this.isPickerShow = false;
}
});
}
_toggle(){
if(this.isMoving) {
return;
}
if(this.isPickerShow) {
this._slideDown();
}
else{
this._slideUp();
}
}
//向父组件提供方法
toggle(){
this._toggle();
}
_prePressHandle(callback){
//通知子组件往上滚
this.pickerWheel.moveUp();
}
_nextPressHandle(callback){
//通知子组件往下滚
this.pickerWheel.moveDown();
}
_pickerCancel() {
this._toggle();
this.state.onPickerCancel();
}
_pickerFinish(){
this._toggle();
this.state.onPickerDone(this.pickedValue);
}
_renderParallelWheel(pickerData){
let me = this;
return pickerData.map((item, index) => {
return (
{
me.pickedValue.splice(index, 1, value);
//do not set state to another object!! why?
// me.setState({
// selectedValue: me.pickedValue
// });
me.setState({
selectedValue: JSON.parse(JSON.stringify(me.pickedValue))
});
me.state.onValueChange(JSON.parse(JSON.stringify(me.pickedValue)), index);
}} >
{item.map((value, index) => (
)
)}
);
});
}
_getCascadeData(pickerData, pickedValue, firstPickedData, secondPickedData, onInit){
let secondWheelData;
let secondPickedDataIndex;
let thirdWheelData;
let thirdPickedDataIndex;
//only support two and three stage
for(let key in pickerData){
//two stage
if(pickerData[key].constructor === Array){
secondWheelData = pickerData[firstPickedData];
if(onInit){
secondWheelData.forEach(function(v, k){
if(v === pickedValue[1]){
secondPickedDataIndex = k;
}
}.bind(this));
}
else{
secondPickedDataIndex = 0;
}
break;
}
//three stage
else{
secondWheelData = Object.keys(pickerData[firstPickedData]);
if(onInit){
secondWheelData.forEach(function(v, k){
if(v === pickedValue[1]){
secondPickedDataIndex = k;
}
}.bind(this));
}
else{
secondPickedDataIndex = 0;
}
thirdWheelData = pickerData[firstPickedData][secondPickedData];
if(onInit){
thirdWheelData.forEach(function(v, k){
if(v === pickedValue[2]){
thirdPickedDataIndex = k;
}
})
}
else{
thirdPickedDataIndex = 0;
}
break;
}
}
return {
secondWheelData,
secondPickedDataIndex,
thirdWheelData,
thirdPickedDataIndex
}
}
_renderCascadeWheel(pickerData){
let me = this;
let thirdWheel = me.state.thirdWheelData && (
{
//on ios platform 'this' refers to Picker?
me.pickedValue.splice(2, 1, me.state.thirdWheelData[index]);
me.setState({
thirdPickedDataIndex: index,
selectedValue: 'wheel3'+index
});
me.state.onValueChange(JSON.parse(JSON.stringify(me.pickedValue)), 2);
}} >
{me.state.thirdWheelData.map((value, index) => (
)
)}
);
return (
{
let secondWheelData = Object.keys(pickerData[value]);
let cascadeData = me._getCascadeData(pickerData, me.pickedValue, value, secondWheelData[0]);
//when onPicked, this.pickedValue will pass to the parent
//when firstWheel changed, second and third will also change
if(cascadeData.thirdWheelData){
me.pickedValue.splice(0, 3, value, cascadeData.secondWheelData[0], cascadeData.thirdWheelData[0]);
}
else{
me.pickedValue.splice(0, 2, value, cascadeData.secondWheelData[0]);
}
me.setState({
selectedValue: 'wheel1'+value,
firstPickedData: value,
secondWheelData: cascadeData.secondWheelData,
secondPickedDataIndex: 0,
thirdWheelData: cascadeData.thirdWheelData,
thirdPickedDataIndex: 0
});
me.state.onValueChange(JSON.parse(JSON.stringify(me.pickedValue)), 0);
me.refs.secondWheel && me.refs.secondWheel.moveTo && me.refs.secondWheel.moveTo(0);
me.refs.thirdWheel && me.refs.thirdWheel.moveTo && me.refs.thirdWheel.moveTo(0);
}} >
{me.state.firstWheelData.map((value, index) => (
)
)}
{
let thirdWheelData = pickerData[me.state.firstPickedData][me.state.secondWheelData[index]];
if(thirdWheelData){
me.pickedValue.splice(1, 2, me.state.secondWheelData[index], thirdWheelData[0]);
}
else{
me.pickedValue.splice(1, 1, me.state.secondWheelData[index]);
}
me.setState({
secondPickedDataIndex: index,
thirdWheelData,
thirdPickedDataIndex: 0,
selectedValue: 'wheel2'+index
});
me.state.onValueChange(JSON.parse(JSON.stringify(me.pickedValue)), 1);
me.refs.thirdWheel && me.refs.thirdWheel.moveTo && me.refs.thirdWheel.moveTo(0);
}} >
{me.state.secondWheelData.map((value, index) => (
)
)}
{thirdWheel}
);
}
_renderWheel(pickerData){
/*
some sences:
1. single wheel:
[1,2,3,4]
2. two or more:
[
[1,2,3,4],
[5,6,7,8],
...
]
3. two stage cascade:
{
a: [1,2,3,4],
b: [5,6,7,8],
...
}
4. three stage cascade:
{
a: {
a1: [1,2,3,4],
a2: [5,6,7,8],
a3: [9,10,11,12]
},
b: {
b1: [1,2,3,4],
b2: [5,6,7,8],
b3: [9,10,12,12]
}
...
}
we call 1、2 parallel and 3、4 cascade
*/
let wheel = null;
if(this.pickerStyle === 'parallel'){
wheel = this._renderParallelWheel(pickerData);
}
else if(this.pickerStyle === 'cascade'){
wheel = this._renderCascadeWheel(pickerData);
}
return wheel;
}
render(){
/*let pickerBtn = Platform.OS === 'ios' ? null : (
上一个
下一个
);*/
// let pickerBtn = null;
return (
{this.state.pickerCancelBtnText}
{this.state.pickerTitle}
{this.state.pickerBtnText}
{this._renderWheel(this.state.pickerData)}
);
}
};
let styles = StyleSheet.create({
picker: {
width: width,
position: 'absolute',
bottom: 0,
left: 0,
backgroundColor: '#bdc0c7',
overflow: 'hidden'
},
pickerWrap: {
width: width,
flexDirection: 'row'
},
pickerWheel: {
flex: 1
},
pickerToolbar: {
height: 30,
width: width,
backgroundColor: '#e6e6e6',
flexDirection: 'row',
borderTopWidth: 1,
borderBottomWidth: 1,
borderColor: '#c3c3c3',
alignItems: 'center'
},
pickerBtnView: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center'
},
pickerMoveBtn: {
color: '#149be0',
fontSize: 16,
marginLeft: 20
},
pickerCancelBtn: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
marginLeft: 20
},
pickerTitle: {
flex: 4,
color: 'black',
textAlign: 'center'
},
pickerFinishBtn: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
marginRight: 20
},
pickerFinishBtnText: {
fontSize: 16,
color: '#149be0'
}
});