diff --git a/README.md b/README.md index 31a593c689db94f710a6c7e6c60a7b088e6606be..dc9c1465325a362492a2b9645bff68bfed74af3e 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ Needs react-native >= 0.14.2 - selectedValue any - onPickerDone function +####Methods +- toggle show or hide picker, default to be hiden + ###Usage ####Step 1 - install @@ -38,4 +41,66 @@ Needs react-native >= 0.14.2 selectedValue={}//default to be selected value onPickerDone={}//when confirm your choice /> -``` \ No newline at end of file +``` + +###Notice + +####support two modes: + +1. parallel: such as time picker, wheels have no connection with each other + +2. cascade: such as date picker, address picker .etc, when front wheel changed, the behind wheels will all be reset + +####parallel: + +- single wheel: + +```javascript + pickerData = [1,2,3,4]; + selectedValue = 3; +``` + +- two or more wheel: + +```javascript + pickerData = [ + [1,2,3,4], + [5,6,7,8], + ... + ]; + selectedValue = [1, 5]; +``` + +####cascade: + +- two wheel + +```javascript + pickerData = { + { + a: [1,2,3,4], + b: [5,6,7,8], + ... + } + }; + selectedValue = ['a', 2]; +``` + +- three wheel + +```javascript + pickerData = { + 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] + } + ... + }; + selectedValue = ['a', 'a1', 1]; +``` diff --git a/index.js b/index.js index 66300663d41bb0bf44ed02fe64ca1f5e7ea0800f..0b8b05ee605437cd9a81e466ea1744d1560531df 100644 --- a/index.js +++ b/index.js @@ -14,31 +14,78 @@ import React, { import PickerAndroid from 'react-native-picker-android'; let Picker = Platform.OS === 'ios' ? PickerIOS : PickerAndroid; -let PickerItem = Picker.Item; +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, + pickerBtnStyle: PropTypes.any, + pickerToolBarStyle: PropTypes.any, + pickerItemStyle: PropTypes.any, pickerHeight: PropTypes.number, showDuration: PropTypes.number, - pickerData: PropTypes.array, + pickerData: PropTypes.any.isRequired, + selectedValue: PropTypes.any.isRequired, onPickerDone: PropTypes.func } static defaultProps = { - pickerHeight: height/3, + pickerBtnText: '完成', + pickerHeight: 250, showDuration: 300, onPickerDone: ()=>{} } constructor(props, context){ super(props, context); + //the pickedValue must looks like [wheelone's, wheeltwo's, ...] + //this.state.selectedValue may be the result of the first pickerWheel + let pickedValue = this.props.selectedValue; + let pickerData = this.props.pickerData; + let pickerStyle = pickerData.constructor === Array ? 'parallel' : 'cascade'; + let firstWheelData; + let firstPickedData; + let secondWheelData; + let secondPickedDataIndex; + let thirdWheelData; + let thirdPickedDataIndex; + let cascadeData = {}; + if(pickerStyle === 'parallel'){ + //compatible single wheel sence + if(pickedValue.constructor !== Array){ + pickedValue = [pickedValue]; + } + if(pickerData[0].constructor !== Array){ + pickerData = [pickerData]; + } + } + else if(pickerStyle === 'cascade'){ + //only support three stage + firstWheelData = Object.keys(pickerData); + firstPickedData = this.props.selectedValue[0]; + secondPickedData = this.props.selectedValue[1]; + cascadeData = this._getCascadeData(pickerData, pickedValue, firstPickedData, secondPickedData, true); + } this.state = { - selectedValue: this.props.selectedValue, - slideAnim: new Animated.Value(-this.props.pickerHeight) + slideAnim: new Animated.Value(-this.props.pickerHeight), + pickerData, + selectedValue: pickedValue, + //list of first wheel data + firstWheelData, + //first wheel selected value + firstPickedData, + //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 }; + this.pickedValue = pickedValue; + this.pickerStyle = pickerStyle; } _slideUp(){ @@ -100,47 +147,257 @@ export default class PickerAny extends React.Component { } _pickerFinish(){ - let pickedValue = this.pickedValue === undefined ? this.state.selectedValue : this.pickedValue; this._toggle(); - this.props.onPickerDone(pickedValue); + this.props.onPickerDone(this.pickedValue); + } + + _renderParallelWheel(pickerData){ + let me = this; + return pickerData.map((item, index) => { + return ( + + { + me.pickedValue.splice(index, 1, value); + me.setState({ + selectedValue: me.pickedValue + }); + }} > + {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 + }); + }} > + {me.state.thirdWheelData.map((value, index) => ( + ) + )} + + + ); + + return ( + + + { + let secondWheelData = Object.keys(pickerData[value]); + 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: value, + firstPickedData: value, + secondWheelData: cascadeData.secondWheelData, + secondPickedDataIndex: 0, + thirdWheelData: cascadeData.thirdWheelData, + thirdPickedDataIndex: 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 + }); + 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 = Platform.OS === 'ios' ? null : ( 上一个 下一个 - ); + );*/ + let pickerBtn = null; return ( - + {pickerBtn} - 完成 + {this.props.pickerBtnText} - this.pickerWheel = pickerWheel } - selectedValue={this.state.selectedValue} - onValueChange={value => { - this.pickedValue = value; - this.setState({ - selectedValue: value - }); - }} > - {this.props.pickerData.map((value, index) => ( - ) - )} - + + {this._renderWheel(this.state.pickerData)} + ); } @@ -148,13 +405,19 @@ export default class PickerAny extends React.Component { let styles = StyleSheet.create({ picker: { - flex: 1, + width: width, position: 'absolute', bottom: 0, left: 0, backgroundColor: '#bdc0c7', + overflow: 'hidden' + }, + pickerWrap: { width: width, - overflow: 'hidden', + flexDirection: 'row' + }, + pickerWheel: { + flex: 1 }, pickerToolbar: { height: 30, diff --git a/package.json b/package.json index d4895fab932ea3a48827cf8bf06efe4c9f1b91bc..8316143941e578804c07f93fc74c16f2d79f9e7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-picker", - "version": "0.1.2", + "version": "0.2.0", "description": "react-native-picker", "main": "index.js", "scripts": {