Commit 34d81a57 authored by xwenliang's avatar xwenliang

support abreast wheels

parent 01290c20
...@@ -17,6 +17,9 @@ Needs react-native >= 0.14.2 ...@@ -17,6 +17,9 @@ Needs react-native >= 0.14.2
- <b>selectedValue</b> any - <b>selectedValue</b> any
- <b>onPickerDone</b> function - <b>onPickerDone</b> function
####Methods
- <b>toggle</b> show or hide picker, default to be hiden
###Usage ###Usage
####Step 1 - install ####Step 1 - install
...@@ -38,4 +41,66 @@ Needs react-native >= 0.14.2 ...@@ -38,4 +41,66 @@ Needs react-native >= 0.14.2
selectedValue={}//default to be selected value selectedValue={}//default to be selected value
onPickerDone={}//when confirm your choice onPickerDone={}//when confirm your choice
/> />
``` ```
\ No newline at end of file
###Notice
####support two modes:
<b>1. parallel: such as time picker, wheels have no connection with each other</b>
<b>2. cascade: such as date picker, address picker .etc, when front wheel changed, the behind wheels will all be reset</b>
####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];
```
...@@ -14,31 +14,78 @@ import React, { ...@@ -14,31 +14,78 @@ import React, {
import PickerAndroid from 'react-native-picker-android'; import PickerAndroid from 'react-native-picker-android';
let Picker = Platform.OS === 'ios' ? PickerIOS : PickerAndroid; let Picker = Platform.OS === 'ios' ? PickerIOS : PickerAndroid;
let PickerItem = Picker.Item; let PickerItem = Picker.item;
let width = Dimensions.get('window').width; let width = Dimensions.get('window').width;
let height = Dimensions.get('window').height; let height = Dimensions.get('window').height;
export default class PickerAny extends React.Component { export default class PickerAny extends React.Component {
static propTypes = { static propTypes = {
pickerBtnText: PropTypes.string,
pickerBtnStyle: PropTypes.any,
pickerToolBarStyle: PropTypes.any,
pickerItemStyle: PropTypes.any,
pickerHeight: PropTypes.number, pickerHeight: PropTypes.number,
showDuration: PropTypes.number, showDuration: PropTypes.number,
pickerData: PropTypes.array, pickerData: PropTypes.any.isRequired,
selectedValue: PropTypes.any.isRequired,
onPickerDone: PropTypes.func onPickerDone: PropTypes.func
} }
static defaultProps = { static defaultProps = {
pickerHeight: height/3, pickerBtnText: '完成',
pickerHeight: 250,
showDuration: 300, showDuration: 300,
onPickerDone: ()=>{} onPickerDone: ()=>{}
} }
constructor(props, context){ constructor(props, context){
super(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 = { 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(){ _slideUp(){
...@@ -100,47 +147,257 @@ export default class PickerAny extends React.Component { ...@@ -100,47 +147,257 @@ export default class PickerAny extends React.Component {
} }
_pickerFinish(){ _pickerFinish(){
let pickedValue = this.pickedValue === undefined ? this.state.selectedValue : this.pickedValue;
this._toggle(); this._toggle();
this.props.onPickerDone(pickedValue); this.props.onPickerDone(this.pickedValue);
}
_renderParallelWheel(pickerData){
let me = this;
return pickerData.map((item, index) => {
return (
<View style={styles.pickerWheel}>
<Picker
selectedValue={me.state.selectedValue[index]}
onValueChange={value => {
me.pickedValue.splice(index, 1, value);
me.setState({
selectedValue: me.pickedValue
});
}} >
{item.map((value, index) => (
<PickerItem
key={index}
value={value}
label={value}
/>)
)}
</Picker>
</View>
);
});
}
_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 && (
<View style={styles.pickerWheel}>
<Picker
ref={'thirdWheel'}
selectedValue={me.state.thirdPickedDataIndex}
onValueChange={(index) => {
//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) => (
<PickerItem
key={index}
value={index}
label={value}
/>)
)}
</Picker>
</View>
);
return (
<View style={styles.pickerWrap}>
<View style={styles.pickerWheel}>
<Picker
ref={'firstWheel'}
selectedValue={me.state.firstPickedData}
onValueChange={value => {
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) => (
<PickerItem
key={index}
value={value}
label={value}
/>)
)}
</Picker>
</View>
<View style={styles.pickerWheel}>
<Picker
ref={'secondWheel'}
selectedValue={me.state.secondPickedDataIndex}
onValueChange={(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) => (
<PickerItem
key={index}
value={index}
label={value}
/>)
)}
</Picker>
</View>
{thirdWheel}
</View>
);
}
_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(){ render(){
let pickerBtn = Platform.OS === 'ios' ? null : ( /*let pickerBtn = Platform.OS === 'ios' ? null : (
<View style={styles.pickerBtnView}> <View style={styles.pickerBtnView}>
<Text style={styles.pickerMoveBtn} onPress={this._prePressHandle.bind(this)}>上一个</Text> <Text style={styles.pickerMoveBtn} onPress={this._prePressHandle.bind(this)}>上一个</Text>
<Text style={styles.pickerMoveBtn} onPress={this._nextPressHandle.bind(this)}>下一个</Text> <Text style={styles.pickerMoveBtn} onPress={this._nextPressHandle.bind(this)}>下一个</Text>
</View> </View>
); );*/
let pickerBtn = null;
return ( return (
<Animated.View style={[styles.picker, { <Animated.View style={[styles.picker, {
height: this.props.pickerHeight, height: this.props.pickerHeight,
bottom: this.state.slideAnim bottom: this.state.slideAnim
}]}> }]}>
<View style={styles.pickerToolbar}> <View style={[styles.pickerToolbar, this.props.pickerToolBarStyle]}>
{pickerBtn} {pickerBtn}
<View style={styles.pickerFinishBtn}> <View style={styles.pickerFinishBtn}>
<Text style={styles.pickerFinishBtnText} <Text style={[styles.pickerFinishBtnText, this.props.pickerBtnStyle]}
onPress={this._pickerFinish.bind(this)}>完成</Text> onPress={this._pickerFinish.bind(this)}>{this.props.pickerBtnText}</Text>
</View> </View>
</View> </View>
<Picker <View style={styles.pickerWrap}>
ref={pickerWheel => this.pickerWheel = pickerWheel } {this._renderWheel(this.state.pickerData)}
selectedValue={this.state.selectedValue} </View>
onValueChange={value => {
this.pickedValue = value;
this.setState({
selectedValue: value
});
}} >
{this.props.pickerData.map((value, index) => (
<PickerItem
key={index}
value={value}
label={value}
/>)
)}
</Picker>
</Animated.View> </Animated.View>
); );
} }
...@@ -148,13 +405,19 @@ export default class PickerAny extends React.Component { ...@@ -148,13 +405,19 @@ export default class PickerAny extends React.Component {
let styles = StyleSheet.create({ let styles = StyleSheet.create({
picker: { picker: {
flex: 1, width: width,
position: 'absolute', position: 'absolute',
bottom: 0, bottom: 0,
left: 0, left: 0,
backgroundColor: '#bdc0c7', backgroundColor: '#bdc0c7',
overflow: 'hidden'
},
pickerWrap: {
width: width, width: width,
overflow: 'hidden', flexDirection: 'row'
},
pickerWheel: {
flex: 1
}, },
pickerToolbar: { pickerToolbar: {
height: 30, height: 30,
......
{ {
"name": "react-native-picker", "name": "react-native-picker",
"version": "0.1.2", "version": "0.2.0",
"description": "react-native-picker", "description": "react-native-picker",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment