diff --git a/Examples/UIExplorer/PickerAndroidExample.js b/Examples/UIExplorer/PickerAndroidExample.js
index 947a0129e..0f76f6e84 100644
--- a/Examples/UIExplorer/PickerAndroidExample.js
+++ b/Examples/UIExplorer/PickerAndroidExample.js
@@ -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: '',
+ title: '',
description: 'Provides multiple options to choose from, using either a dropdown menu or a dialog.',
},
@@ -38,9 +39,8 @@ const PickerAndroidExample = React.createClass({
selected1: 'key1',
selected2: 'key1',
selected3: 'key1',
- selected4: 'key1',
color: 'red',
- mode: PickerAndroid.MODE_DIALOG,
+ mode: Picker.MODE_DIALOG,
};
},
@@ -48,93 +48,93 @@ const PickerAndroidExample = React.createClass({
render: function() {
return (
-
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
- Tap here to switch between dialog/dropdown.
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
+
- 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.
-
-
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
);
},
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;
diff --git a/Libraries/Components/Picker/Picker.js b/Libraries/Components/Picker/Picker.js
new file mode 100644
index 000000000..9db560fb9
--- /dev/null
+++ b/Libraries/Components/Picker/Picker.js
@@ -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:
+ *
+ * this.setState({language: lang})}>
+ *
+ *
+ *
+ */
+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 {this.props.children};
+ } else if (Platform.OS === 'android') {
+ return {this.props.children};
+ } else {
+ return ;
+ }
+ },
+});
+
+/**
+ * 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;
diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js
new file mode 100644
index 000000000..2e95b32f1
--- /dev/null
+++ b/Libraries/Components/Picker/PickerAndroid.android.js
@@ -0,0 +1,141 @@
+/**
+ * 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 PickerAndroid
+ * @flow
+ */
+
+'use strict';
+
+var ColorPropType = require('ColorPropType');
+var React = require('React');
+var ReactChildren = require('ReactChildren');
+var ReactPropTypes = require('ReactPropTypes');
+var StyleSheet = require('StyleSheet');
+var StyleSheetPropType = require('StyleSheetPropType');
+var View = require('View');
+var ViewStylePropTypes = require('ViewStylePropTypes');
+
+var processColor = require('processColor');
+var requireNativeComponent = require('requireNativeComponent');
+
+var REF_PICKER = 'picker';
+var MODE_DIALOG = 'dialog';
+var MODE_DROPDOWN = 'dropdown';
+
+var pickerStyleType = StyleSheetPropType({
+ ...ViewStylePropTypes,
+ color: ColorPropType,
+});
+
+type Event = Object;
+
+/**
+ * Not exposed as a public API - use instead.
+ */
+var PickerAndroid = React.createClass({
+
+ propTypes: {
+ ...View.propTypes,
+ style: pickerStyleType,
+ selectedValue: React.PropTypes.any,
+ enabled: ReactPropTypes.bool,
+ mode: ReactPropTypes.oneOf(['dialog', 'dropdown']),
+ onValueChange: ReactPropTypes.func,
+ prompt: ReactPropTypes.string,
+ testID: ReactPropTypes.string,
+ },
+
+ getInitialState: function() {
+ return this._stateFromProps(this.props);
+ },
+
+ componentWillReceiveProps: function(nextProps) {
+ this.setState(this._stateFromProps(nextProps));
+ },
+
+ // Translate prop and children into stuff that the native picker understands.
+ _stateFromProps: function(props) {
+ var selectedIndex = 0;
+ let items = ReactChildren.map(props.children, (child, index) => {
+ if (child.props.value === props.selectedValue) {
+ selectedIndex = index;
+ }
+ let childProps = {
+ value: child.props.value,
+ label: child.props.label,
+ };
+ if (child.props.color) {
+ childProps.color = processColor(child.props.color);
+ }
+ return childProps;
+ });
+ return {selectedIndex, items};
+ },
+
+ render: function() {
+ var Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
+
+ var nativeProps = {
+ enabled: this.props.enabled,
+ items: this.state.items,
+ mode: this.props.mode,
+ onSelect: this._onChange,
+ prompt: this.props.prompt,
+ selected: this.state.selectedIndex,
+ testID: this.props.testID,
+ style: [styles.pickerAndroid, this.props.style],
+ };
+
+ return ;
+ },
+
+ _onChange: function(event: Event) {
+ if (this.props.onValueChange) {
+ var position = event.nativeEvent.position;
+ if (position >= 0) {
+ var value = this.props.children[position].props.value;
+ this.props.onValueChange(value);
+ } else {
+ this.props.onValueChange(null);
+ }
+ }
+
+ // The picker is a controlled component. This means we expect the
+ // on*Change handlers to be in charge of updating our
+ // `selectedValue` prop. That way they can also
+ // disallow/undo/mutate the selection of certain values. In other
+ // words, the embedder of this component should be the source of
+ // truth, not the native component.
+ if (this.refs[REF_PICKER] && this.state.selectedIndex !== event.nativeEvent.position) {
+ this.refs[REF_PICKER].setNativeProps({selected: this.state.selectedIndex});
+ }
+ },
+});
+
+var styles = StyleSheet.create({
+ pickerAndroid: {
+ // The picker will conform to whatever width is given, but we do
+ // have to set the component's height explicitly on the
+ // surrounding view to ensure it gets rendered.
+ // TODO would be better to export a native constant for this,
+ // like in iOS the RCTDatePickerManager.m
+ height: 50,
+ },
+});
+
+var cfg = {
+ nativeOnly: {
+ items: true,
+ selected: true,
+ }
+}
+var DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg);
+var DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg);
+
+module.exports = PickerAndroid;
diff --git a/Libraries/Components/Picker/PickerAndroid.ios.js b/Libraries/Components/Picker/PickerAndroid.ios.js
new file mode 100644
index 000000000..fc5898828
--- /dev/null
+++ b/Libraries/Components/Picker/PickerAndroid.ios.js
@@ -0,0 +1,13 @@
+/**
+ * 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 PickerAndroid
+ */
+'use strict';
+
+module.exports = require('UnimplementedView');
diff --git a/Libraries/Components/PickerAndroid/PickerAndroid.js b/Libraries/Components/PickerAndroid/PickerAndroid.js
deleted file mode 100644
index 1ec105ca4..000000000
--- a/Libraries/Components/PickerAndroid/PickerAndroid.js
+++ /dev/null
@@ -1,213 +0,0 @@
-/**
- * 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 PickerAndroid
- * @flow
- */
-
-'use strict';
-
-var ColorPropType = require('ColorPropType');
-var React = require('React');
-var ReactChildren = require('ReactChildren');
-var ReactPropTypes = require('ReactPropTypes');
-var StyleSheetPropType = require('StyleSheetPropType');
-var View = require('View');
-var ViewStylePropTypes = require('ViewStylePropTypes');
-
-var processColor = require('processColor');
-var requireNativeComponent = require('requireNativeComponent');
-
-var MODE_DIALOG = 'dialog';
-var MODE_DROPDOWN = 'dropdown';
-var REF_PICKER = 'picker';
-
-var pickerStyleType = StyleSheetPropType({
- ...ViewStylePropTypes,
- color: ColorPropType,
-});
-
-type Items = {
- selected: number;
- items: any[];
-};
-
-type Event = Object;
-
-/**
- * Individual selectable item in a Picker.
- */
-var Item = React.createClass({
-
- propTypes: {
- /**
- * Color of this item's text.
- */
- color: ColorPropType,
- /**
- * Text to display for this item.
- */
- text: ReactPropTypes.string.isRequired,
- /**
- * The value to be passed to picker's `onSelect` callback when this item is selected.
- */
- value: ReactPropTypes.string,
- /**
- * If `true`, this item is selected and shown in the picker.
- * Usually this is set based on state.
- */
- selected: ReactPropTypes.bool,
- /**
- * Used to locate this view in end-to-end tests.
- */
- testID: ReactPropTypes.string,
- },
-
- render: function() {
- throw new Error('Picker items should never be rendered');
- },
-
-});
-
-/**
- * - A React component that renders the native Picker widget on Android. The items
- * that can be selected are specified as children views of type Item. Example usage:
- *
- *
- *
- *
- *
- */
-var PickerAndroid = React.createClass({
-
- propTypes: {
- ...View.propTypes,
- style: pickerStyleType,
- /**
- * If set to false, the picker will be disabled, i.e. the user will not be able to make a
- * selection.
- */
- enabled: ReactPropTypes.bool,
- /**
- * Specifies how to display the selection items when the user taps on the picker:
- *
- * - dialog: Show a modal dialog
- * - dropdown: Shows a dropdown anchored to the picker view
- */
- mode: ReactPropTypes.oneOf([MODE_DIALOG, MODE_DROPDOWN]),
- /**
- * 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
- */
- onSelect: ReactPropTypes.func,
- /**
- * Prompt string for this picker, currently only used in `dialog` mode as the title of the
- * dialog.
- */
- prompt: ReactPropTypes.string,
- /**
- * Used to locate this view in end-to-end tests.
- */
- testID: ReactPropTypes.string,
- },
-
- statics: {
- Item: Item,
- MODE_DIALOG: MODE_DIALOG,
- MODE_DROPDOWN: MODE_DROPDOWN,
- },
-
- getDefaultProps: function() {
- return {
- mode: MODE_DIALOG,
- };
- },
-
- render: function() {
- var Picker = this.props.mode === MODE_DROPDOWN ? DropdownPicker : DialogPicker;
-
- var { selected, items } = this._getItems();
-
- var nativeProps = {
- enabled: this.props.enabled,
- items: items,
- mode: this.props.mode,
- onSelect: this._onSelect,
- prompt: this.props.prompt,
- selected: selected,
- style: this.props.style,
- testID: this.props.testID,
- };
-
- return ;
- },
-
- /**
- * Transform this view's children into an array of items to be passed to the native component.
- * Since we're traversing the children, also determine the selected position.
- *
- * @returns an object with two keys:
- *
- * - `selected` (number) - the index of the selected item
- * - `items` (array) - the items of this picker, as an array of strings
- */
- _getItems: function(): Items {
- var items = [];
- var selected = 0;
- ReactChildren.forEach(this.props.children, function(child, index) {
- var childProps = Object.assign({}, child.props);
- if (childProps.color) {
- childProps.color = processColor(childProps.color);
- }
- items.push(childProps);
- if (childProps.selected) {
- selected = index;
- }
- });
- return {
- selected: selected,
- items: items,
- };
- },
-
- _onSelect: function(event: Event) {
- if (this.props.onSelect) {
- var position = event.nativeEvent.position;
- if (position >= 0) {
- var value = this.props.children[position].props.value;
- this.props.onSelect(value, position);
- } else {
- this.props.onSelect(null, position);
- }
- }
-
- // The native Picker has changed, but the props haven't (yet). If
- // the handler decides to not accept the new value or do something
- // else with it we might end up in a bad state, so we reset the
- // selection on the native component.
- // tl;dr: PickerAndroid is a controlled component.
- var { selected } = this._getItems();
- if (this.refs[REF_PICKER]) {
- this.refs[REF_PICKER].setNativeProps({selected: selected});
- }
- },
-
-});
-
-var cfg = {
- nativeOnly: {
- items: true,
- selected: true,
- }
-}
-var DropdownPicker = requireNativeComponent('AndroidDropdownPicker', PickerAndroid, cfg);
-var DialogPicker = requireNativeComponent('AndroidDialogPicker', PickerAndroid, cfg);
-
-module.exports = PickerAndroid;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index da90b75c0..6efc9af3c 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -25,7 +25,7 @@ var ReactNative = {
get Modal() { return require('Modal'); },
get Navigator() { return require('Navigator'); },
get NavigatorIOS() { return require('NavigatorIOS'); },
- get PickerAndroid() { return require('PickerAndroid'); },
+ get Picker() { return require('Picker'); },
get PickerIOS() { return require('PickerIOS'); },
get ProgressBarAndroid() { return require('ProgressBarAndroid'); },
get ProgressViewIOS() { return require('ProgressViewIOS'); },
diff --git a/Libraries/react-native/react-native.js.flow b/Libraries/react-native/react-native.js.flow
index 52d7eeddb..a0c20f5e0 100644
--- a/Libraries/react-native/react-native.js.flow
+++ b/Libraries/react-native/react-native.js.flow
@@ -37,7 +37,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
Modal: require('Modal'),
Navigator: require('Navigator'),
NavigatorIOS: require('NavigatorIOS'),
- PickerAndroid: require('PickerAndroid'),
+ Picker: require('Picker'),
PickerIOS: require('PickerIOS'),
ProgressBarAndroid: require('ProgressBarAndroid'),
ProgressViewIOS: require('ProgressViewIOS'),
diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
index fe2f23cd0..2c8c24038 100644
--- a/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
+++ b/ReactAndroid/src/main/java/com/facebook/react/views/picker/ReactPickerManager.java
@@ -128,7 +128,7 @@ public abstract class ReactPickerManager extends SimpleViewManager
}
TextView textView = (TextView) convertView;
- textView.setText(item.getString("text"));
+ textView.setText(item.getString("label"));
if (!isDropdown && mPrimaryTextColor != null) {
textView.setTextColor(mPrimaryTextColor);
} else if (item.hasKey("color") && !item.isNull("color")) {