Skip to content

Commit

Permalink
Add Android React Native Checkbox
Browse files Browse the repository at this point in the history
Reviewed By: achen1

Differential Revision: D5281736

fbshipit-source-id: 9a3c93eeace2d80be4ddbd4ffc3258c1d3637480
  • Loading branch information
Becky Van Bussel authored and facebook-github-bot committed Aug 25, 2017
1 parent dacb1fb commit 84b11dd
Show file tree
Hide file tree
Showing 11 changed files with 437 additions and 0 deletions.
127 changes: 127 additions & 0 deletions Libraries/Components/CheckBox/CheckBox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* Copyright (c) 2017-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 CheckBox
* @flow
* @format
*/
'use strict';

const NativeMethodsMixin = require('NativeMethodsMixin');
const PropTypes = require('prop-types');
const React = require('React');
const StyleSheet = require('StyleSheet');
const ViewPropTypes = require('ViewPropTypes');

const createReactClass = require('create-react-class');
const requireNativeComponent = require('requireNativeComponent');

type DefaultProps = {
value: boolean,
disabled: boolean,
};

/**
* Renders a boolean input.
*
* This is a controlled component that requires an `onValueChange` callback that
* updates the `value` prop in order for the component to reflect user actions.
* If the `value` prop is not updated, the component will continue to render
* the supplied `value` prop instead of the expected result of any user actions.
*
* @keyword checkbox
* @keyword toggle
*/
// $FlowFixMe(>=0.41.0)
let CheckBox = createReactClass({
displayName: 'CheckBox',
propTypes: {
...ViewPropTypes,
/**
* The value of the checkbox. If true the checkbox will be turned on.
* Default value is false.
*/
value: PropTypes.bool,
/**
* If true the user won't be able to toggle the checkbox.
* Default value is false.
*/
disabled: PropTypes.bool,
/**
* Used in case the props change removes the component.
*/
onChange: PropTypes.func,
/**
* Invoked with the new value when the value changes.
*/
onValueChange: PropTypes.func,
/**
* Used to locate this view in end-to-end tests.
*/
testID: PropTypes.string,
},

getDefaultProps: function(): DefaultProps {
return {
value: false,
disabled: false,
};
},

mixins: [NativeMethodsMixin],

_rctCheckBox: {},
_onChange: function(event: Object) {
this._rctCheckBox.setNativeProps({value: this.props.value});
// Change the props after the native props are set in case the props
// change removes the component
this.props.onChange && this.props.onChange(event);
this.props.onValueChange &&
this.props.onValueChange(event.nativeEvent.value);
},

render: function() {
let props = {...this.props};
props.onStartShouldSetResponder = () => true;
props.onResponderTerminationRequest = () => false;
props.enabled = !this.props.disabled;
props.on = this.props.value;
props.style = [styles.rctCheckBox, this.props.style];

return (
<RCTCheckBox
{...props}
ref={ref => {
/* $FlowFixMe(>=0.53.0 site=react_native_fb) This comment suppresses an
* error when upgrading Flow's support for React. Common errors found
* when upgrading Flow's React support are documented at
* https://fburl.com/eq7bs81w */
this._rctCheckBox = ref;
}}
onChange={this._onChange}
/>
);
},
});

let styles = StyleSheet.create({
rctCheckBox: {
height: 32,
width: 32,
},
});

let RCTCheckBox = requireNativeComponent('AndroidCheckBox', CheckBox, {
nativeOnly: {
onChange: true,
on: true,
enabled: true,
},
});

module.exports = CheckBox;
1 change: 1 addition & 0 deletions Libraries/react-native/react-native-implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const ReactNative = {
get ActivityIndicator() { return require('ActivityIndicator'); },
get ART() { return require('ReactNativeART'); },
get Button() { return require('Button'); },
get CheckBox() { return require('CheckBox'); },
get DatePickerIOS() { return require('DatePickerIOS'); },
get DrawerLayoutAndroid() { return require('DrawerLayoutAndroid'); },
get FlatList() { return require('FlatList'); },
Expand Down
129 changes: 129 additions & 0 deletions RNTester/js/CheckBoxExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/**
* Copyright (c) 2017-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.
*
* @flow
* @providesModule CheckBoxExample
* @format
*/
'use strict';

const React = require('react');
const ReactNative = require('react-native');
const {CheckBox, Text, View} = ReactNative;

class BasicCheckBoxExample extends React.Component<{}, $FlowFixMeState> {
state = {
trueCheckBoxIsOn: true,
falseCheckBoxIsOn: false,
};

render() {
return (
<View>
<CheckBox
onValueChange={value => this.setState({falseCheckBoxIsOn: value})}
style={{marginBottom: 10}}
value={this.state.falseCheckBoxIsOn}
/>
<CheckBox
onValueChange={value => this.setState({trueCheckBoxIsOn: value})}
value={this.state.trueCheckBoxIsOn}
/>
</View>
);
}
}

class DisabledCheckBoxExample extends React.Component<{}, $FlowFixMeState> {
render() {
return (
<View>
<CheckBox disabled={true} style={{marginBottom: 10}} value={true} />
<CheckBox disabled={true} value={false} />
</View>
);
}
}

class EventCheckBoxExample extends React.Component<{}, $FlowFixMeState> {
state = {
eventCheckBoxIsOn: false,
eventCheckBoxRegressionIsOn: true,
};

render() {
return (
<View style={{flexDirection: 'row', justifyContent: 'space-around'}}>
<View>
<CheckBox
onValueChange={value => this.setState({eventCheckBoxIsOn: value})}
style={{marginBottom: 10}}
value={this.state.eventCheckBoxIsOn}
/>
<CheckBox
onValueChange={value => this.setState({eventCheckBoxIsOn: value})}
style={{marginBottom: 10}}
value={this.state.eventCheckBoxIsOn}
/>
<Text>
{this.state.eventCheckBoxIsOn ? 'On' : 'Off'}
</Text>
</View>
<View>
<CheckBox
onValueChange={value =>
this.setState({eventCheckBoxRegressionIsOn: value})}
style={{marginBottom: 10}}
value={this.state.eventCheckBoxRegressionIsOn}
/>
<CheckBox
onValueChange={value =>
this.setState({eventCheckBoxRegressionIsOn: value})}
style={{marginBottom: 10}}
value={this.state.eventCheckBoxRegressionIsOn}
/>
<Text>
{this.state.eventCheckBoxRegressionIsOn ? 'On' : 'Off'}
</Text>
</View>
</View>
);
}
}

let examples = [
{
title: 'CheckBoxes can be set to true or false',
render(): React.Element<any> {
return <BasicCheckBoxExample />;
},
},
{
title: 'CheckBoxes can be disabled',
render(): React.Element<any> {
return <DisabledCheckBoxExample />;
},
},
{
title: 'Change events can be detected',
render(): React.Element<any> {
return <EventCheckBoxExample />;
},
},
{
title: 'CheckBoxes are controlled components',
render(): React.Element<any> {
return <CheckBox />;
},
},
];

exports.title = '<CheckBox>';
exports.displayName = 'CheckBoxExample';
exports.description = 'Native boolean input';
exports.examples = examples;
4 changes: 4 additions & 0 deletions RNTester/js/RNTesterList.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const ComponentExamples: Array<RNTesterExample> = [
key: 'ButtonExample',
module: require('./ButtonExample'),
},
{
key: 'CheckBoxExample',
module: require('./CheckBoxExample'),
},
{
key: 'FlatListExample',
module: require('./FlatListExample'),
Expand Down
1 change: 1 addition & 0 deletions ReactAndroid/src/main/java/com/facebook/react/shell/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ android_library(
react_native_target("java/com/facebook/react/modules/websocket:websocket"),
react_native_target("java/com/facebook/react/uimanager:uimanager"),
react_native_target("java/com/facebook/react/views/art:art"),
react_native_target("java/com/facebook/react/views/checkbox:checkbox"),
react_native_target("java/com/facebook/react/views/drawer:drawer"),
react_native_target("java/com/facebook/react/views/image:image"),
react_native_target("java/com/facebook/react/views/modal:modal"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.views.art.ARTRenderableViewManager;
import com.facebook.react.views.art.ARTSurfaceViewManager;
import com.facebook.react.views.checkbox.ReactCheckBoxManager;
import com.facebook.react.views.drawer.ReactDrawerLayoutManager;
import com.facebook.react.views.image.ReactImageManager;
import com.facebook.react.views.modal.ReactModalHostManager;
Expand Down Expand Up @@ -309,6 +310,7 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
viewManagers.add(ARTRenderableViewManager.createARTGroupViewManager());
viewManagers.add(ARTRenderableViewManager.createARTShapeViewManager());
viewManagers.add(ARTRenderableViewManager.createARTTextViewManager());
viewManagers.add(new ReactCheckBoxManager());
viewManagers.add(new ReactDialogPickerManager());
viewManagers.add(new ReactDrawerLayoutManager());
viewManagers.add(new ReactDropdownPickerManager());
Expand Down
17 changes: 17 additions & 0 deletions ReactAndroid/src/main/java/com/facebook/react/views/checkbox/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
include_defs("//ReactAndroid/DEFS")

android_library(
name = "checkbox",
srcs = glob(["*.java"]),
visibility = [
"PUBLIC",
],
deps = [
react_native_dep("third-party/android/support/v4:lib-support-v4"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/common:common"),
react_native_target("java/com/facebook/react/uimanager:uimanager"),
react_native_target("java/com/facebook/react/uimanager/annotations:annotations"),
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2017-present, Facebook, Inc. All rights reserved.
*
* <p>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.
*/
package com.facebook.react.views.checkbox;

import android.content.Context;
import android.widget.CheckBox;

/** CheckBox that has its value controlled by JS. */
/*package*/ class ReactCheckBox extends CheckBox {

private boolean mAllowChange;

public ReactCheckBox(Context context) {
super(context);
mAllowChange = true;
}

@Override
public void setChecked(boolean checked) {
if (mAllowChange) {
mAllowChange = false;
super.setChecked(checked);
}
}

/*package*/ void setOn(boolean on) {
// If the checkbox has a different value than the value sent by JS, we must change it.
if (isChecked() != on) {
super.setChecked(on);
}
mAllowChange = true;
}
}
Loading

0 comments on commit 84b11dd

Please sign in to comment.