diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a105709 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.xcuserstate +project.xcworkspace +xcuserdata +UserInterfaceState.xcuserstate +project.xcworkspace/ +xcuserdata/ +UserInterface.xcuserstate \ No newline at end of file diff --git a/RCTRefreshControl.android.js b/RCTRefreshControl.android.js deleted file mode 100644 index 6c4716a..0000000 --- a/RCTRefreshControl.android.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Stub of RCTRefreshControl for Android. - * - * @providesModule RCTRefreshControl - * @flow - */ -'use strict'; - -var warning = require('warning'); - -var RCTRefreshControl = { - test: function() { - warning("Not yet implemented for Android."); - } -}; - -module.exports = RCTRefreshControl; diff --git a/RCTRefreshControl.h b/RCTRefreshControl.h index 8d679c3..fc29cee 100644 --- a/RCTRefreshControl.h +++ b/RCTRefreshControl.h @@ -1,5 +1,5 @@ #import "RCTBridgeModule.h" -@interface RCTRefreshControl : NSObject +@interface RCTRefresher : NSObject @end diff --git a/RCTRefreshControl.ios.js b/RCTRefreshControl.js similarity index 76% rename from RCTRefreshControl.ios.js rename to RCTRefreshControl.js index efd98be..eed8a49 100644 --- a/RCTRefreshControl.ios.js +++ b/RCTRefreshControl.js @@ -8,8 +8,9 @@ var React = require('react-native'); var { DeviceEventEmitter, NativeModules: { - RefreshControl, - } + Refresher, + }, + processColor } = React; /** @@ -30,11 +31,11 @@ var RCTRefreshControl = { configure: function(configs, callback) { var nodeHandle = React.findNodeHandle(configs.node); var options = { - tintColor: configs.tintColor, - activityIndicatorViewColor: configs.activityIndicatorViewColor + tintColor: processColor(configs.tintColor), + activityIndicatorViewColor: processColor(configs.activityIndicatorViewColor) }; - - RefreshControl.configure(nodeHandle, options, (error) => { + + Refresher.configure(nodeHandle, options, (error) => { if (!error) { callbacks[nodeHandle] = callback; } @@ -42,7 +43,7 @@ var RCTRefreshControl = { }, endRefreshing: function(node) { var nodeHandle = React.findNodeHandle(node); - RefreshControl.endRefreshing(nodeHandle); + Refresher.endRefreshing(nodeHandle); } }; diff --git a/RCTRefreshControl.m b/RCTRefreshControl.m index a03a3ba..86b1256 100644 --- a/RCTRefreshControl.m +++ b/RCTRefreshControl.m @@ -5,11 +5,10 @@ #import "RCTBridge.h" #import "RCTConvert.h" #import "RCTScrollView.h" -#import "RCTSparseArray.h" #import "RCTUIManager.h" #import "RCTEventDispatcher.h" -@implementation RCTRefreshControl +@implementation RCTRefresher #pragma mark - @@ -24,45 +23,45 @@ - (dispatch_queue_t)methodQueue { RCT_EXPORT_METHOD(configure:(nonnull NSNumber *)reactTag options:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback) { - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { - + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + UIView *view = viewRegistry[reactTag]; if (!view) { RCTLogError(@"Cannot find view with tag #%@", reactTag); return; } - + UIScrollView *scrollView = ((RCTScrollView *)view).scrollView; - + ODRefreshControl *refreshControl = [[ODRefreshControl alloc] initInScrollView:scrollView]; refreshControl.tag = [reactTag integerValue]; // Maybe something better - + UIColor *tintColor = options[@"tintColor"]; // TODO: activityIndicatorViewStyle UIColor *activityIndicatorViewColor = options[@"activityIndicatorViewColor"]; - + if (tintColor) refreshControl.tintColor = [RCTConvert UIColor:tintColor]; if (activityIndicatorViewColor) refreshControl.activityIndicatorViewColor = [RCTConvert UIColor:activityIndicatorViewColor]; - + [refreshControl addTarget:self action:@selector(dropViewDidBeginRefreshing:) forControlEvents:UIControlEventValueChanged]; - + callback(@[[NSNull null], reactTag]); }]; } RCT_EXPORT_METHOD(beginRefreshing:(nonnull NSNumber *)reactTag) { - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { - + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + UIView *view = viewRegistry[reactTag]; if (!view) { RCTLogError(@"Cannot find view with tag #%@", reactTag); return; } - + UIScrollView *scrollView = ((RCTScrollView *)view).scrollView; - + ODRefreshControl *refreshControl = (ODRefreshControl *)[scrollView viewWithTag:[reactTag integerValue]]; - + dispatch_async(dispatch_get_main_queue(), ^{ [refreshControl beginRefreshing]; }); @@ -70,18 +69,18 @@ - (dispatch_queue_t)methodQueue { } RCT_EXPORT_METHOD(endRefreshing:(nonnull NSNumber *)reactTag) { - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { - + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + UIView *view = viewRegistry[reactTag]; if (!view) { RCTLogError(@"Cannot find view with tag #%@", reactTag); return; } - + UIScrollView *scrollView = ((RCTScrollView *)view).scrollView; - + ODRefreshControl *refreshControl = (ODRefreshControl *)[scrollView viewWithTag:[reactTag integerValue]]; - + dispatch_async(dispatch_get_main_queue(), ^{ [refreshControl endRefreshing]; }); @@ -97,7 +96,7 @@ - (NSDictionary *)constantsToExport { - (void)dropViewDidBeginRefreshing:(ODRefreshControl *)refreshControl { [self.bridge.eventDispatcher sendDeviceEventWithName:@"dropViewDidBeginRefreshing" body:@(refreshControl.tag)]; - + /* double delayInSeconds = 3.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); diff --git a/RCTRefreshControl.xcodeproj/project.pbxproj b/RCTRefreshControl.xcodeproj/project.pbxproj index 8f17af8..43d3254 100644 --- a/RCTRefreshControl.xcodeproj/project.pbxproj +++ b/RCTRefreshControl.xcodeproj/project.pbxproj @@ -73,9 +73,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 58B511DA1A9E6C8500147676 /* RCTRefreshControl */ = { + 58B511DA1A9E6C8500147676 /* RCTRefresher */ = { isa = PBXNativeTarget; - buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTRefreshControl" */; + buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTRefresher" */; buildPhases = ( 58B511D71A9E6C8500147676 /* Sources */, 58B511D81A9E6C8500147676 /* Frameworks */, @@ -85,7 +85,7 @@ ); dependencies = ( ); - name = RCTRefreshControl; + name = RCTRefresher; productName = RCTDataManager; productReference = 134814201AA4EA6300B7C361 /* libRCTRefreshControl.a */; productType = "com.apple.product-type.library.static"; @@ -116,7 +116,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 58B511DA1A9E6C8500147676 /* RCTRefreshControl */, + 58B511DA1A9E6C8500147676 /* RCTRefresher */, ); }; /* End PBXProject section */ @@ -219,7 +219,7 @@ ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = RCTRefreshControl; + PRODUCT_NAME = RCTRefresher; SKIP_INSTALL = YES; }; name = Debug; @@ -235,7 +235,7 @@ ); LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = RCTRefreshControl; + PRODUCT_NAME = RCTRefresher; SKIP_INSTALL = YES; }; name = Release; @@ -252,7 +252,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTRefreshControl" */ = { + 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTRefresher" */ = { isa = XCConfigurationList; buildConfigurations = ( 58B511F01A9E6C8500147676 /* Debug */, diff --git a/README.md b/README.md index 279c66b..23d69bb 100644 --- a/README.md +++ b/README.md @@ -1,104 +1,99 @@ # RCTRefreshControl +[![npm version](https://badge.fury.io/js/react-native-refresh-control.svg)](https://badge.fury.io/js/react-native-refresh-control) -A pull down to refresh control for react native. +A pull down to refresh control for react native. This project use a native-bridging way to implement the Pull-To-Refresh, absolutely **NO** jitter and lagging compared with those package which implemented using Javascript. -## Screen Shot +This is a **forked** project from [Shuangzuan/RCTRefreshControl](https://github.com/Shuangzuan/RCTRefreshControl). +This project added a more user-friendly way to use this package, and I also fix some bugs of the original project. -![Screen Shot](screen-shot.gif) +![react-refreshcontrol](https://cloud.githubusercontent.com/assets/4535844/11009604/9845be08-84ae-11e5-8fe0-1037c057ce05.gif) ## Installation -1. Run `npm install react-refresh-control --save` in your project directory. +1. Run `npm install react-native-refresh-control --save` in your project directory. 2. Drag `RCTRefreshControl.xcodeproj` to your project on Xcode. 3. Click on your main project file (the one that represents the .xcodeproj) select Build Phases and drag `libRCTRefreshControl.a` from the Products folder inside the `RCTRefreshControl.xcodeproj`. -4. Add `var RCTRefreshControl = require('react-refresh-control');` to your code. +4. Add `var RCTRefreshControl = require('react-native-refresh-control');` to your code. + +__I will yield the package name once [Shuangzuan](https://github.com/Shuangzuan)requests __. ## Usage +It is very easy to use, just use `RCTRefreshControl.ListView` as the `React.ListView` +or use `RCTRefreshControl.ScrollView` as the `React.ScrollView` + +The simple difference between the `ListView` and `ScrollView` in React Native is that you can pass your `onRefresh` event handler into `RCTRefreshControl.ListView` and `RCTRefreshControl.ScrollView`. + +The event handler below stop the refreshing state of the `ListView` in 2 seconds once the user pull down the `ListView` and triggered the refresh. -```javascript +```jsx +var onRefreshHandler = (stopRefreshAnimation) => { + setTimeout(stopRefreshAnimation, 2000); +}; +``` + +And use like this +```jsx + +``` + +## Sample Code + +**Using fewer lines to implement a Pull-To-Refresh** + +```jsx 'use strict'; -var React = require('react-native'); -var TimerMixin = require('react-timer-mixin'); -var RCTRefreshControl = require('react-refresh-control'); -var { - AppRegistry, - ListView, - ScrollView, - StyleSheet, - Text, - View +import React from 'react-native'; +const { + View, + ListView } = React; -var SCROLLVIEW = 'ScrollView'; -var LISTVIEW = 'ListView'; +import RCTRefreshControl from 'react-refresh-control'; -var RCTRefreshControlDemo = React.createClass({ - mixins: [TimerMixin], - getInitialState: function() { - var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); - return { - dataSource: ds.cloneWithRows(['#484848', '#2F9C0A', '#05A5D1']), +class MyApp extends React.Component { + constructor(props) { + super(props); + + var dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); + this.state = { + dataSource: dataSource.cloneWithRows(['#484848', '#2F9C0A', '#05A5D1']) }; - }, - componentDidMount: function() { - // ScrollView - RCTRefreshControl.configure({ - node: this.refs[SCROLLVIEW], - tintColor: '#05A5D1', - activityIndicatorViewColor: '#05A5D1' - }, () => { - this.setTimeout(() => { - RCTRefreshControl.endRefreshing(this.refs[SCROLLVIEW]); - }, 2000); - }); - - // ListView - RCTRefreshControl.configure({ - node: this.refs[LISTVIEW] - }, () => { - this.setTimeout(() => { - RCTRefreshControl.endRefreshing(this.refs[LISTVIEW]); - }, 2000); - }); - }, - render: function() { + } + onRefresh(stopRefresh) { + console.log(this.state); + setTimeout(stopRefresh, 2000); + } + renderRow(data) { return ( - - + + ); + } + render() { + return ( + + + - - - { - var color = rowData; - return ( - - ); - }} - /> + ); } -}); +} -var styles = StyleSheet.create({ - container: { - flex: 1, - flexDirection: 'row' - } -}); - -AppRegistry.registerComponent('RCTRefreshControlDemo', () => RCTRefreshControlDemo); +React.AppRegistry.registerComponent('RCTRefreshControlDemo', () => RCTRefreshControlDemo); ``` ---- - ## License Available under the MIT license. See the LICENSE file for more informatiion. diff --git a/index.ios.js b/index.ios.js new file mode 100644 index 0000000..944e105 --- /dev/null +++ b/index.ios.js @@ -0,0 +1,77 @@ +'use strict'; + +import React from 'react-native'; +const { + Component, + StyleSheet, + Text, + View, + ScrollView, + ListView +} = React; + +import RCTRefreshControl from './RCTRefreshControl'; + +let randId = () => (Math.random() + 1).toString(36).substring(7); + +const ELEMENT_ID = randId(); + +var style = StyleSheet.create({ + rootView: { + flex: 1 + } +}); + +let RCTRefreshControlView = {}; + +class RCTRefreshControlScrollView extends Component { + componentDidMount() { + RCTRefreshControl.configure({ + node: this.refs[ELEMENT_ID], + tintColor: this.props.tintColor, + activityIndicatorViewColor: this.props.activityIndicatorViewColor + }, () => { + if (this.props.onRefresh) { + this.props.onRefresh(() => { + RCTRefreshControl.endRefreshing(this.refs[ELEMENT_ID]); + }); + } + }); + } + render() { + return ( + + {this.props.children} + + ); + } + + scrollTo(...args) { + this.refs[ELEMENT_ID].scrollTo(...args); + } +} + +class RCTRefreshControlViewListView extends Component { + componentDidMount() { + RCTRefreshControl.configure({ + node: this.refs[ELEMENT_ID], + tintColor: this.props.tintColor, + activityIndicatorViewColor: this.props.activityIndicatorViewColor + }, () => { + if (this.props.onRefresh) { + this.props.onRefresh(() => { + RCTRefreshControl.endRefreshing(this.refs[ELEMENT_ID]); + }); + } + }); + } + render() { + return ( + + ); + } +} +RCTRefreshControl.ScrollView = RCTRefreshControlScrollView; +RCTRefreshControl.ListView = RCTRefreshControlViewListView; + +module.exports = RCTRefreshControl; diff --git a/package.json b/package.json index ef4fb83..95558fa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "react-refresh-control", + "name": "react-native-refresh-control", "description": "A pull down to refresh control for react native.", - "version": "2.0.5", + "version": "2.0.6", "keywords": [ "react-component", "react-native", @@ -10,16 +10,16 @@ "control" ], "license": "MIT", - "main": "RCTRefreshControl.ios.js", + "main": "index.ios.js", "repository": { "type": "git", - "url": "git@github.com:Shuangzuan/RCTRefreshControl.git" + "url": "git@github.com:DickyT/RCTRefreshControl.git" }, "author": "Shuangzuan", "maintainers": [ { - "name": "Shuangzuan", - "email": "shuangzuan.he@icloud.com" + "name": "DickyT", + "email": "me@idickyt.com" } ] }