Summary:
RN offers checkbox component on android: https://facebook.github.io/react-native/docs/checkbox.html

The Checkbox colors for checked and unchecked states cannot be controlled from JS at the moment; this PR adds support for that.

The essence of changing colors for the states is this:

```
ColorStateList cls = new ColorStateList(
        new int[][] {
                new int[] { -android.R.attr.state_checked }, // unchecked
                new int[] {  android.R.attr.state_checked }  // checked
        },
        new int[] {
                uncheckedColor,
                checkedColor
        }
);
checkBox.setSupportButtonTintList(cls);
```

Because of this, I did it so that both colors have to provided together in an object. This is similar to [switch](https://facebook.github.io/react-native/docs/switch#trackcolor)
Pull Request resolved: https://github.com/facebook/react-native/pull/18300

Differential Revision: D14180218

Pulled By: cpojer

fbshipit-source-id: 88a9d1faf061c0651e3e28950f697535b90fbfd4
This commit is contained in:
Vojtech Novak 2019-02-21 20:11:58 -08:00 коммит произвёл Facebook Github Bot
Родитель 17082d92cf
Коммит 976f4be457
4 изменённых файлов: 78 добавлений и 3 удалений

Просмотреть файл

@ -42,6 +42,7 @@ type NativeProps = $ReadOnly<{|
on?: ?boolean,
enabled?: boolean,
tintColors: {|true: ?number, false: ?number|} | typeof undefined,
|}>;
type CheckBoxNativeType = Class<NativeComponent<NativeProps>>;

Просмотреть файл

@ -11,6 +11,7 @@
const React = require('React');
const StyleSheet = require('StyleSheet');
const processColor = require('processColor');
const AndroidCheckBoxNativeComponent = require('AndroidCheckBoxNativeComponent');
const nullthrows = require('nullthrows');
@ -19,6 +20,7 @@ const setAndForwardRef = require('setAndForwardRef');
import type {ViewProps} from 'ViewPropTypes';
import type {SyntheticEvent} from 'CoreEventTypes';
import type {NativeComponent} from 'ReactNative';
import type {ColorValue} from 'StyleSheetTypes';
type CheckBoxEvent = SyntheticEvent<
$ReadOnly<{|
@ -51,6 +53,7 @@ type NativeProps = $ReadOnly<{|
on?: ?boolean,
enabled?: boolean,
tintColors: {|true: ?number, false: ?number|} | typeof undefined,
|}>;
type CheckBoxNativeType = Class<NativeComponent<NativeProps>>;
@ -74,6 +77,11 @@ type Props = $ReadOnly<{|
* Used to get the ref for the native checkbox
*/
forwardedRef?: ?React.Ref<CheckBoxNativeType>,
/**
* Controls the colors the checkbox has in checked and unchecked states.
*/
tintColors?: {|true?: ?ColorValue, false?: ?ColorValue|},
|}>;
/**
@ -150,8 +158,24 @@ class CheckBox extends React.Component<Props> {
this.props.onValueChange(event.nativeEvent.value);
};
getTintColors(tintColors) {
return tintColors
? {
true: processColor(tintColors.true),
false: processColor(tintColors.false),
}
: undefined;
}
render() {
const {disabled: _, value: __, style, forwardedRef, ...props} = this.props;
const {
disabled: _,
value: __,
tintColors,
style,
forwardedRef,
...props
} = this.props;
const disabled = this.props.disabled ?? false;
const value = this.props.value ?? false;
@ -161,9 +185,9 @@ class CheckBox extends React.Component<Props> {
onResponderTerminationRequest: () => false,
enabled: !disabled,
on: value,
tintColors: this.getTintColors(tintColors),
style: [styles.rctCheckBox, style],
};
return (
<AndroidCheckBoxNativeComponent
{...nativeProps}

Просмотреть файл

@ -33,10 +33,12 @@ class BasicCheckBoxExample extends React.Component<BasicProps, BasicState> {
onValueChange={value => this.setState({falseCheckBoxIsOn: value})}
style={styles.checkbox}
value={this.state.falseCheckBoxIsOn}
tintColors={{false: 'red'}}
/>
<CheckBox
onValueChange={value => this.setState({trueCheckBoxIsOn: value})}
value={this.state.trueCheckBoxIsOn}
tintColors={{true: 'green'}}
/>
</View>
);
@ -120,7 +122,8 @@ exports.displayName = 'CheckBoxExample';
exports.description = 'Native boolean input';
exports.examples = [
{
title: 'CheckBoxes can be set to true or false',
title:
'CheckBoxes can be set to true or false, and the color of both states can be specified.',
render(): React.Element<any> {
return <BasicCheckBoxExample />;
},

Просмотреть файл

@ -7,15 +7,22 @@
package com.facebook.react.views.checkbox;
import android.content.Context;
import android.content.res.ColorStateList;
import android.support.v4.widget.CompoundButtonCompat;
import android.support.v7.widget.TintContextWrapper;
import android.util.TypedValue;
import android.widget.CompoundButton;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import javax.annotation.Nullable;
/** View manager for {@link ReactCheckBox} components. */
public class ReactCheckBoxManager extends SimpleViewManager<ReactCheckBox> {
@ -72,4 +79,44 @@ public class ReactCheckBoxManager extends SimpleViewManager<ReactCheckBox> {
view.setOn(on);
view.setOnCheckedChangeListener(ON_CHECKED_CHANGE_LISTENER);
}
private static int getThemeColor(final Context context, String colorId) {
final TypedValue value = new TypedValue();
context.getTheme().resolveAttribute(getIdentifier(context, colorId), value, true);
return value.data;
}
/**
* The appcompat-v7 BUCK dep is listed as a provided_dep, which complains that
* com.facebook.react.R doesn't exist. Since the attributes are provided from a parent, we can access
* those attributes dynamically.
*/
private static int getIdentifier(Context context, String name) {
return context.getResources().getIdentifier(name, "attr", context.getPackageName());
}
@ReactProp(name = "tintColors")
public void setTintColors(ReactCheckBox view, @Nullable ReadableMap colorsMap) {
String defaultColorIdOfCheckedState = "colorAccent";
int trueColor = colorsMap == null || !colorsMap.hasKey("true") ?
getThemeColor(view.getContext(), defaultColorIdOfCheckedState) : colorsMap.getInt("true");
String defaultColorIdOfUncheckedState = "colorPrimaryDark";
int falseColor = colorsMap == null || !colorsMap.hasKey("false") ?
getThemeColor(view.getContext(), defaultColorIdOfUncheckedState) : colorsMap.getInt("false");
ColorStateList csl = new ColorStateList(
new int[][]{
new int[]{android.R.attr.state_checked},
new int[]{-android.R.attr.state_checked}
},
new int[]{
trueColor,
falseColor,
}
);
CompoundButtonCompat.setButtonTintList(view, csl);
}
}