diff --git a/Examples/UIExplorer/SliderExample.js b/Examples/UIExplorer/SliderExample.js new file mode 100644 index 000000000..0ff4f6713 --- /dev/null +++ b/Examples/UIExplorer/SliderExample.js @@ -0,0 +1,57 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule SliderExample + */ +'use strict'; + +var React = require('react-native'); +var { + Slider, + Text, + StyleSheet, + View, +} = React; + +var SliderExample = React.createClass({ + getInitialState() { + return { + value: 0, + }; + }, + + render() { + return ( + + + {this.state.value} + + this.setState({value: value})} /> + + ); + } +}); + +var styles = StyleSheet.create({ + slider: { + height: 10, + margin: 10, + }, + text: { + fontSize: 14, + textAlign: 'center', + fontWeight: 'bold', + margin: 10, + }, +}); + +exports.title = ''; +exports.description = 'Slider input for numeric values'; +exports.examples = [ + { + title: 'Slider', + render() { return ; } + } +]; diff --git a/Examples/UIExplorer/UIExplorerList.js b/Examples/UIExplorer/UIExplorerList.js index 277517983..e04edcab6 100644 --- a/Examples/UIExplorer/UIExplorerList.js +++ b/Examples/UIExplorer/UIExplorerList.js @@ -35,6 +35,7 @@ var EXAMPLES = [ require('./GeolocationExample'), require('./TabBarExample'), require('./SwitchExample'), + require('./SliderExample'), ]; var UIExplorerList = React.createClass({ diff --git a/Libraries/Components/Slider/Slider.js b/Libraries/Components/Slider/Slider.js new file mode 100644 index 000000000..80f631c45 --- /dev/null +++ b/Libraries/Components/Slider/Slider.js @@ -0,0 +1,83 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule Slider + */ +'use strict'; + +var NativeMethodsMixin = require('NativeMethodsMixin'); +var PropTypes = require('ReactPropTypes'); +var React = require('React'); +var ReactIOSViewAttributes = require('ReactIOSViewAttributes'); +var StyleSheet = require('StyleSheet'); +var View = require('View'); + +var createReactIOSNativeComponentClass = + require('createReactIOSNativeComponentClass'); +var merge = require('merge'); + +var Slider = React.createClass({ + mixins: [NativeMethodsMixin], + + propTypes: { + /** + * Used to style and layout the `Slider`. See `StyleSheet.js` and + * `ViewStylePropTypes.js` for more info. + */ + style: View.propTypes.style, + + /** + * Initial value of the slider. The value should be between 0 and 1. + * Default value is 0. + * + * *This is not a controlled component*, e.g. if you don't update + * the value, the component won't be reseted to it's inital value. + */ + value: PropTypes.number, + + /** + * Callback continuously called while the user is dragging the slider. + */ + onValueChange: PropTypes.func, + + /** + * Callback called when the user finishes changing the value (e.g. when + * the slider is released). + */ + onSlidingComplete: PropTypes.func, + }, + + _onValueChange: function(event) { + this.props.onChange && this.props.onChange(event); + if (event.nativeEvent.continuous) { + this.props.onValueChange && + this.props.onValueChange(event.nativeEvent.value); + } else { + this.props.onSlidingComplete && event.nativeEvent.value !== undefined && + this.props.onSlidingComplete(event.nativeEvent.value); + } + }, + + render: function() { + return ( + + ); + } +}); + +var styles = StyleSheet.create({ + slider: { + height: 40, + }, +}); + +var RKSlider = createReactIOSNativeComponentClass({ + validAttributes: merge(ReactIOSViewAttributes.UIView, {value: true}), + uiViewClassName: 'RCTSlider', +}); + +module.exports = Slider; diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js index 5aafb28ce..7f7edaf72 100644 --- a/Libraries/react-native/react-native.js +++ b/Libraries/react-native/react-native.js @@ -18,6 +18,7 @@ var ReactNative = { PixelRatio: require('PixelRatio'), ScrollView: require('ScrollView'), ActivityIndicatorIOS: require('ActivityIndicatorIOS'), + Slider: require('Slider'), StatusBarIOS: require('StatusBarIOS'), StyleSheet: require('StyleSheet'), SwitchIOS: require('SwitchIOS'), diff --git a/ReactKit/ReactKit.xcodeproj/project.pbxproj b/ReactKit/ReactKit.xcodeproj/project.pbxproj index dd9a452a0..48cac5ded 100644 --- a/ReactKit/ReactKit.xcodeproj/project.pbxproj +++ b/ReactKit/ReactKit.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ 58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */; }; 14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F362081AABD06A001CE568 /* RCTSwitch.m */; }; 14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */; }; + 14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; }; 830A229E1A66C68A008503DA /* RCTRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 830A229D1A66C68A008503DA /* RCTRootView.m */; }; 830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 830BA4541A8E3BDA00D53203 /* RCTCache.m */; }; 832348161A77A5AA00B55238 /* Layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FC71A68125100A75B9A /* Layout.c */; }; @@ -131,6 +132,8 @@ 14F362081AABD06A001CE568 /* RCTSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitch.m; sourceTree = ""; }; 14F362091AABD06A001CE568 /* RCTSwitchManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSwitchManager.h; sourceTree = ""; }; 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitchManager.m; sourceTree = ""; }; + 14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSliderManager.h; sourceTree = ""; }; + 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSliderManager.m; sourceTree = ""; }; 830213F31A654E0800B993E6 /* RCTBridgeModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeModule.h; sourceTree = ""; }; 830A229C1A66C68A008503DA /* RCTRootView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootView.h; sourceTree = ""; }; 830A229D1A66C68A008503DA /* RCTRootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootView.m; sourceTree = ""; }; @@ -214,6 +217,8 @@ 14F362081AABD06A001CE568 /* RCTSwitch.m */, 14F362091AABD06A001CE568 /* RCTSwitchManager.h */, 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */, + 14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */, + 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */, 13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */, 58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */, 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */, @@ -421,6 +426,7 @@ 13B0801F1A69489C00A75B9A /* RCTTextFieldManager.m in Sources */, 134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */, 13E067591A70F44B002CDEE1 /* UIView+ReactKit.m in Sources */, + 14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */, 83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */, 83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */, 13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */, diff --git a/ReactKit/Views/RCTSliderManager.h b/ReactKit/Views/RCTSliderManager.h new file mode 100644 index 000000000..1088ec569 --- /dev/null +++ b/ReactKit/Views/RCTSliderManager.h @@ -0,0 +1,7 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#import "RCTViewManager.h" + +@interface RCTSliderManager : RCTViewManager + +@end diff --git a/ReactKit/Views/RCTSliderManager.m b/ReactKit/Views/RCTSliderManager.m new file mode 100644 index 000000000..8561c0a97 --- /dev/null +++ b/ReactKit/Views/RCTSliderManager.m @@ -0,0 +1,43 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#import "RCTSliderManager.h" + +#import "RCTBridge.h" +#import "RCTEventDispatcher.h" +#import "UIView+ReactKit.h" + +@implementation RCTSliderManager + +- (UIView *)view +{ + UISlider *slider = [[UISlider alloc] init]; + [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged]; + [slider addTarget:self action:@selector(sliderTouchEnd:) forControlEvents:UIControlEventTouchUpInside]; + return slider; +} + +- (void)sliderValueChanged:(UISlider *)sender +{ + NSDictionary *event = @{ + @"target": sender.reactTag, + @"value": @(sender.value), + @"continuous": @YES, + }; + + [self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event]; +} + +- (void)sliderTouchEnd:(UISlider *)sender +{ + NSDictionary *event = @{ + @"target": sender.reactTag, + @"value": @(sender.value), + @"continuous": @NO, + }; + + [self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event]; +} + +RCT_EXPORT_VIEW_PROPERTY(value); + +@end