Skip to content

Instantly share code, notes, and snippets.

@kyryloz
Last active February 28, 2018 15:21
Show Gist options
  • Save kyryloz/f4ce1eaa1fc3cb3f3b9b9bf05c9b2cc3 to your computer and use it in GitHub Desktop.
Save kyryloz/f4ce1eaa1fc3cb3f3b9b9bf05c9b2cc3 to your computer and use it in GitHub Desktop.
NumberPicker react-native bridge (Android)
Wraps Android's `android.widget.NumberPicker`.
Supported 'Nothing' selection, which appears as first item in the NumberPicker.
// omitted
export const reactComponent = () => (
<NumberPickerAndroid
style={styles.numberPicker} // set width and height
initialValues={{
minValue: 1,
maxValue: 10,
initialValue: 3,
}}
onChange={value => {}}
wrapSelectorWheel={false}
/>
)
// omitted
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new NumberPickerReactPackage());
}
// omitted
import PropTypes from 'prop-types'
import React from 'react'
import {
requireNativeComponent,
ViewPropTypes,
} from 'react-native'
import {
compose,
withHandlers,
} from 'recompose'
const componentInterface = {
name: 'NumberPickerAndroid',
propTypes: {
initialValues: PropTypes.shape({
minValue: PropTypes.number,
maxValue: PropTypes.number,
initialValue: PropTypes.number,
}),
wrapSelectorWheel: PropTypes.bool,
onChange: PropTypes.func,
...ViewPropTypes,
},
}
const NativeNumberPickerAndroid = requireNativeComponent('NumberPickerAndroid', componentInterface)
const handleValueChange = ({ onChange }) => event => onChange(event.nativeEvent.value)
export const NumberPickerAndroid = compose(
withHandlers({
handleValueChange,
}),
)(props => (
<NativeNumberPickerAndroid
{...props}
onChange={props.handleValueChange}
/>
))
package com.project.nativemodules.numberpicker;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class NumberPickerReactPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
List<ViewManager> viewManagers = new ArrayList<>();
viewManagers.add(new NumberPickerViewManager());
return viewManagers;
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
package com.project.nativemodules.numberpicker;
import android.widget.NumberPicker;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class NumberPickerViewManager extends SimpleViewManager<ReactNumberPickerView> {
private static final String EVENT_NAME = "onChange";
@Override
public String getName() {
return "NumberPickerAndroid";
}
@Override
protected ReactNumberPickerView createViewInstance(ThemedReactContext reactContext) {
return new ReactNumberPickerView(reactContext);
}
@Override
public Map<String, Object> getExportedCustomBubblingEventTypeConstants() {
Map<String, Map<String, String>> eventBinding = MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", EVENT_NAME));
return MapBuilder.<String, Object>builder()
.put(EVENT_NAME, eventBinding)
.build();
}
public void addEventEmitters(final ThemedReactContext reactContext, ReactNumberPickerView view) {
view.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker numberPicker, int oldValue, int newValue) {
final WritableMap eventData = Arguments.createMap();
eventData.putInt("value", newValue == numberPicker.getMinValue() ? -1 : newValue);
reactContext.getNativeModule(UIManagerModule.class)
.getEventDispatcher()
.dispatchEvent(new Event(numberPicker.getId()) {
@Override
public String getEventName() {
return EVENT_NAME;
}
@Override
public void dispatch(RCTEventEmitter emitter) {
emitter.receiveEvent(getViewTag(), getEventName(), eventData);
}
});
}
});
}
@ReactProp(name = "initialValues")
public void setInitialValues(ReactNumberPickerView view, ReadableMap map) {
view.setMinValue(map.getInt("minValue") - 1);
view.setMaxValue(map.getInt("maxValue"));
view.setValue(map.getInt("initialValue"));
invalidateDisplayedValues(view);
}
@ReactProp(name = "wrapSelectorWheel")
public void setWrapSelectorWheel(ReactNumberPickerView view, boolean wrap) {
view.setWrapSelectorWheel(wrap);
}
private void invalidateDisplayedValues(ReactNumberPickerView view) {
List<String> displayedValues = new ArrayList<>();
displayedValues.add("Nothing");
for (int i = view.getMinValue() + 1; i <= view.getMaxValue(); i++) {
displayedValues.add(String.valueOf(i));
}
view.setDisplayedValues(displayedValues.toArray(new String[0]));
}
}
package com.project.nativemodules.numberpicker;
import android.content.Context;
import android.widget.NumberPicker;
public class ReactNumberPickerView extends NumberPicker {
public ReactNumberPickerView(Context context) {
super(context);
setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment