Permalink
Browse files

Add a cross-platform Picker

Summary:
The basic API is consistent with iOS; there are several platform-specific props.

Also fixed the flickering when a value is selected.

public

Reviewed By: bestander

Differential Revision: D2871092

fb-gh-sync-id: f5cdf6858cb7344b28ee46954cb6b0a3b144b646
  • Loading branch information...
mkonicek authored and facebook-github-bot-3 committed Jan 29, 2016
1 parent c33e852 commit 1dd5ba7021c13f3475097db5652f8f4e5e2469f1
@@ -16,20 +16,21 @@
'use strict';
const React = require('react-native');
+const StyleSheet = require('StyleSheet');
const UIExplorerBlock = require('UIExplorerBlock');
const UIExplorerPage = require('UIExplorerPage');
const {
- PickerAndroid,
+ Picker,
Text,
TouchableWithoutFeedback,
} = React;
-const Item = PickerAndroid.Item;
+const Item = Picker.Item;
-const PickerAndroidExample = React.createClass({
+const PickerExample = React.createClass({
statics: {
- title: '<PickerAndroid>',
+ title: '<Picker>',
description: 'Provides multiple options to choose from, using either a dropdown menu or a dialog.',
},
@@ -38,103 +39,102 @@ const PickerAndroidExample = React.createClass({
selected1: 'key1',
selected2: 'key1',
selected3: 'key1',
- selected4: 'key1',
color: 'red',
- mode: PickerAndroid.MODE_DIALOG,
+ mode: Picker.MODE_DIALOG,
};
},
displayName: 'Android Picker',
render: function() {
return (
- <UIExplorerPage title="<PickerAndroid>">
+ <UIExplorerPage title="<Picker>">
<UIExplorerBlock title="Basic Picker">
- <PickerAndroid
- style={{width: 100, height: 56}}
- onSelect={this.onSelect.bind(this, 'selected1')}>
- <Item text="hello" value="key0" selected={this.state.selected1 === 'key0'} />
- <Item text="world" value="key1" selected={this.state.selected1 === 'key1'} />
- </PickerAndroid>
+ <Picker
+ style={styles.picker}
+ selectedValue={this.state.selected1}
+ onValueChange={this.onValueChange.bind(this, 'selected1')}>
+ <Item label="hello" value="key0" />
+ <Item label="world" value="key1" />
+ </Picker>
</UIExplorerBlock>
<UIExplorerBlock title="Disabled picker">
- <PickerAndroid style={{width: 100, height: 56}} enabled={false}>
- <Item text="hello" value="key0" selected={this.state.selected1 === 'key0'} />
- <Item text="world" value="key1" selected={this.state.selected1 === 'key1'} />
- </PickerAndroid>
+ <Picker style={styles.picker} enabled={false} selectedValue={this.state.selected1}>
+ <Item label="hello" value="key0" />
+ <Item label="world" value="key1" />
+ </Picker>
</UIExplorerBlock>
<UIExplorerBlock title="Dropdown Picker">
- <PickerAndroid
- style={{width: 100, height: 56}}
- onSelect={this.onSelect.bind(this, 'selected2')}
+ <Picker
+ style={styles.picker}
+ selectedValue={this.state.selected2}
+ onValueChange={this.onValueChange.bind(this, 'selected2')}
mode="dropdown">
- <Item text="hello" value="key0" selected={this.state.selected2 === 'key0'} />
- <Item text="world" value="key1" selected={this.state.selected2 === 'key1'} />
- </PickerAndroid>
- </UIExplorerBlock>
- <UIExplorerBlock title="Alternating Picker">
- <PickerAndroid
- style={{width: 100, height: 56}}
- onSelect={this.onSelect.bind(this, 'selected3')}
- mode={this.state.mode}>
- <Item text="hello" value="key0" selected={this.state.selected3 === 'key0'} />
- <Item text="world" value="key1" selected={this.state.selected3 === 'key1'} />
- </PickerAndroid>
- <TouchableWithoutFeedback onPress={this.changeMode}>
- <Text>Tap here to switch between dialog/dropdown.</Text>
- </TouchableWithoutFeedback>
+ <Item label="hello" value="key0" />
+ <Item label="world" value="key1" />
+ </Picker>
</UIExplorerBlock>
<UIExplorerBlock title="Picker with prompt message">
- <PickerAndroid
- style={{width: 100, height: 56}}
- onSelect={this.onSelect.bind(this, 'selected4')}
+ <Picker
+ style={styles.picker}
+ selectedValue={this.state.selected3}
+ onValueChange={this.onValueChange.bind(this, 'selected3')}
prompt="Pick one, just one">
- <Item text="hello" value="key0" selected={this.state.selected4 === 'key0'} />
- <Item text="world" value="key1" selected={this.state.selected4 === 'key1'} />
- </PickerAndroid>
+ <Item label="hello" value="key0" />
+ <Item label="world" value="key1" />
+ </Picker>
</UIExplorerBlock>
<UIExplorerBlock title="Picker with no listener">
- <PickerAndroid style={{width: 100, height: 56}}>
- <Item text="hello" value="key0" />
- <Item text="world" value="key1" />
- </PickerAndroid>
+ <Picker style={styles.picker}>
+ <Item label="hello" value="key0" />
+ <Item label="world" value="key1" />
+ </Picker>
<Text>
- You can not change the value of this picker because it doesn't set a selected prop on
- its items.
+ Cannot change the value of this picker because it doesn't update selectedValue.
</Text>
</UIExplorerBlock>
<UIExplorerBlock title="Colorful pickers">
- <PickerAndroid style={{width: 100, height: 56, color: 'black'}}
- onSelect={this.onSelect.bind(this, 'color')}
+ <Picker
+ style={[styles.picker, {color: 'white', backgroundColor: '#333'}]}
+ selectedValue={this.state.color}
+ onValueChange={this.onValueChange.bind(this, 'color')}
mode="dropdown">
- <Item text="red" color="red" value="red" selected={this.state.color === 'red'}/>
- <Item text="green" color="green" value="green" selected={this.state.color === 'green'}/>
- <Item text="blue" color="blue" value="blue" selected={this.state.color === 'blue'}/>
- </PickerAndroid>
- <PickerAndroid style={{width: 100, height: 56}}
- onSelect={this.onSelect.bind(this, 'color')}
+ <Item label="red" color="red" value="red" />
+ <Item label="green" color="green" value="green" />
+ <Item label="blue" color="blue" value="blue" />
+ </Picker>
+ <Picker
+ style={styles.picker}
+ selectedValue={this.state.color}
+ onValueChange={this.onValueChange.bind(this, 'color')}
mode="dialog">
- <Item text="red" color="red" value="red" selected={this.state.color === 'red'}/>
- <Item text="green" color="green" value="green" selected={this.state.color === 'green'}/>
- <Item text="blue" color="blue" value="blue" selected={this.state.color === 'blue'} />
- </PickerAndroid>
+ <Item label="red" color="red" value="red" />
+ <Item label="green" color="green" value="green" />
+ <Item label="blue" color="blue" value="blue" />
+ </Picker>
</UIExplorerBlock>
</UIExplorerPage>
);
},
changeMode: function() {
- const newMode = this.state.mode === PickerAndroid.MODE_DIALOG
- ? PickerAndroid.MODE_DROPDOWN
- : PickerAndroid.MODE_DIALOG;
+ const newMode = this.state.mode === Picker.MODE_DIALOG
+ ? Picker.MODE_DROPDOWN
+ : Picker.MODE_DIALOG;
this.setState({mode: newMode});
},
- onSelect: function(key: string, value: string) {
+ onValueChange: function(key: string, value: string) {
const newState = {};
newState[key] = value;
this.setState(newState);
},
});
-module.exports = PickerAndroidExample;
+var styles = StyleSheet.create({
+ picker: {
+ width: 100,
+ },
+});
+
+module.exports = PickerExample;
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Picker
+ * @flow
+ */
+
+'use strict';
+
+var ColorPropType = require('ColorPropType');
+var PickerIOS = require('PickerIOS');
+var PickerAndroid = require('PickerAndroid');
+var Platform = require('Platform');
+var React = require('React');
+var StyleSheet = require('StyleSheet');
+var StyleSheetPropType = require('StyleSheetPropType');
+var TextStylePropTypes = require('TextStylePropTypes');
+var UnimplementedView = require('UnimplementedView');
+var View = require('View');
+var ViewStylePropTypes = require('ViewStylePropTypes');
+
+var itemStylePropType = StyleSheetPropType(TextStylePropTypes);
+
+var pickerStyleType = StyleSheetPropType({
+ ...ViewStylePropTypes,
+ color: ColorPropType,
+});
+
+var MODE_DIALOG = 'dialog';
+var MODE_DROPDOWN = 'dropdown';
+
+/**
+ * Renders the native picker component on iOS and Android. Example:
+ *
+ * <Picker
+ * selectedValue={this.state.language}
+ * onValueChange={(lang) => this.setState({language: lang})}>
+ * <Picker.Item label="Java" value="java" />
+ * <Picker.Item label="JavaScript" value="js" />
+ * </Picker>
+ */
+var Picker = React.createClass({
+
+ statics: {
+ /**
+ * On Android, display the options in a dialog.
+ */
+ MODE_DIALOG: MODE_DIALOG,
+ /**
+ * On Android, display the options in a dropdown (this is the default).
+ */
+ MODE_DROPDOWN: MODE_DROPDOWN,
+ },
+
+ getDefaultProps: function() {
+ return {
+ mode: MODE_DIALOG,
+ };
+ },
+
+ propTypes: {
+ ...View.propTypes,
+ style: pickerStyleType,
+ /**
+ * Value matching value of one of the items. Can be a string or an integer.
+ */
+ selectedValue: React.PropTypes.any,
+ /**
+ * Callback for when an item is selected. This is called with the following parameters:
+ * - `itemValue`: the `value` prop of the item that was selected
+ * - `itemPosition`: the index of the selected item in this picker
+ */
+ onValueChange: React.PropTypes.func,
+ /**
+ * If set to false, the picker will be disabled, i.e. the user will not be able to make a
+ * selection.
+ * @platform android
+ */
+ enabled: React.PropTypes.bool,
+ /**
+ * On Android, specifies how to display the selection items when the user taps on the picker:
+ * - 'dialog': Show a modal dialog. This is the default.
+ * - 'dropdown': Shows a dropdown anchored to the picker view
+ *
+ * @platform android
+ */
+ mode: React.PropTypes.oneOf([MODE_DIALOG, MODE_DROPDOWN]),
+ /**
+ * Style to apply to each of the item labels.
+ * @platform ios
+ */
+ itemStyle: itemStylePropType,
+ /**
+ * Prompt string for this picker, used on Android in dialog mode as the title of the dialog.
+ * @platform android
+ */
+ prompt: React.PropTypes.string,
+ /**
+ * Used to locate this view in end-to-end tests.
+ */
+ testID: React.PropTypes.string,
+ },
+
+ render: function() {
+ if (Platform.OS === 'ios') {
+ return <PickerIOS {...this.props}>{this.props.children}</PickerIOS>;
+ } else if (Platform.OS === 'android') {
+ return <PickerAndroid {...this.props}>{this.props.children}</PickerAndroid>;
+ } else {
+ return <UnimplementedView />;
+ }
+ },
+});
+
+/**
+ * Individual selectable item in a Picker.
+ */
+Picker.Item = React.createClass({
+
+ propTypes: {
+ /**
+ * Text to display for this item.
+ */
+ label: React.PropTypes.string.isRequired,
+ /**
+ * The value to be passed to picker's `onValueChange` callback when
+ * this item is selected. Can be a string or an integer.
+ */
+ value: React.PropTypes.any,
+ /**
+ * Color of this item's text.
+ * @platform android
+ */
+ color: ColorPropType,
+ /**
+ * Used to locate the item in end-to-end tests.
+ */
+ testID: React.PropTypes.string,
+ },
+
+ render: function() {
+ // The items are not rendered directly
+ throw null;
+ },
+});
+
+module.exports = Picker;
Oops, something went wrong.

0 comments on commit 1dd5ba7

Please sign in to comment.