mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-26 07:04:05 +08:00
Cross platform PullToRefreshView component
Summary: Both iOS and Android currently support some sort of native pull to refresh control but the API was very different. I tried implementing a component based on PullToRefreshViewAndroid but that works on both platforms. I liked the idea of wrapping the ListView or ScrollView with the PullToRefreshView component and allow styling the refresh view with platform specific props if needed. I also like the fact that 'refreshing' is a controlled prop so there is no need to keep a ref to the component or to the stopRefreshing function. It is a pretty rough start so I'm looking for feedback and ideas to improve on the API before cleaning up everything. On iOS we could probably deprecate the onRefreshStart property of the ScrollView and implement the native stuff in a PullToRefreshViewManager. We could then add props to customize the look of the UIRefreshControl (tintColor). We could also deprecate the Android only component and remove it later. Closes https://github.com/facebook/react-native/pull/4915 Reviewed By: svcscm Differential Revision: D2799246 Pulled By: nicklockwood fb-gh-sync-id: 75872c12143ddbc05cc91900ab4612e477ca5765
This commit is contained in:
committed by
facebook-github-bot-5
parent
86af597c2e
commit
44f7a00e95
19
React/Views/RCTRefreshControl.h
Normal file
19
React/Views/RCTRefreshControl.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTComponent.h"
|
||||
|
||||
@interface RCTRefreshControl : UIRefreshControl
|
||||
|
||||
@property (nonatomic, copy) NSString *title;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onRefresh;
|
||||
|
||||
@end
|
||||
54
React/Views/RCTRefreshControl.m
Normal file
54
React/Views/RCTRefreshControl.m
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
#import "RCTRefreshControl.h"
|
||||
|
||||
#import "RCTUtils.h"
|
||||
|
||||
@implementation RCTRefreshControl
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
[self addTarget:self action:@selector(refreshControlValueChanged) forControlEvents:UIControlEventValueChanged];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
|
||||
- (NSString *)title
|
||||
{
|
||||
return self.attributedTitle.string;
|
||||
}
|
||||
|
||||
- (void)setTitle:(NSString *)title
|
||||
{
|
||||
self.attributedTitle = [[NSAttributedString alloc] initWithString:title];
|
||||
}
|
||||
|
||||
- (void)setRefreshing:(BOOL)refreshing
|
||||
{
|
||||
if (super.refreshing != refreshing) {
|
||||
if (refreshing) {
|
||||
[self beginRefreshing];
|
||||
} else {
|
||||
[self endRefreshing];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)refreshControlValueChanged
|
||||
{
|
||||
if (_onRefresh) {
|
||||
_onRefresh(nil);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
14
React/Views/RCTRefreshControlManager.h
Normal file
14
React/Views/RCTRefreshControlManager.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTRefreshControlManager : RCTViewManager
|
||||
|
||||
@end
|
||||
28
React/Views/RCTRefreshControlManager.m
Normal file
28
React/Views/RCTRefreshControlManager.m
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
|
||||
#import "RCTRefreshControlManager.h"
|
||||
|
||||
#import "RCTRefreshControl.h"
|
||||
|
||||
@implementation RCTRefreshControlManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [RCTRefreshControl new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
|
||||
|
||||
@end
|
||||
@@ -14,6 +14,7 @@
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
#import "RCTRefreshControl.h"
|
||||
#import "RCTUIManager.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "UIView+Private.h"
|
||||
@@ -410,20 +411,31 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
||||
|
||||
- (void)insertReactSubview:(UIView *)view atIndex:(__unused NSInteger)atIndex
|
||||
{
|
||||
RCTAssert(_contentView == nil, @"RCTScrollView may only contain a single subview");
|
||||
_contentView = view;
|
||||
[_scrollView addSubview:view];
|
||||
if ([view isKindOfClass:[RCTRefreshControl class]]) {
|
||||
_scrollView.refreshControl = (RCTRefreshControl*)view;
|
||||
} else {
|
||||
RCTAssert(_contentView == nil, @"RCTScrollView may only contain a single subview");
|
||||
_contentView = view;
|
||||
[_scrollView addSubview:view];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeReactSubview:(UIView *)subview
|
||||
{
|
||||
RCTAssert(_contentView == subview, @"Attempted to remove non-existent subview");
|
||||
_contentView = nil;
|
||||
[subview removeFromSuperview];
|
||||
if ([subview isKindOfClass:[RCTRefreshControl class]]) {
|
||||
_scrollView.refreshControl = nil;
|
||||
} else {
|
||||
RCTAssert(_contentView == subview, @"Attempted to remove non-existent subview");
|
||||
_contentView = nil;
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<UIView *> *)reactSubviews
|
||||
{
|
||||
if (_contentView && _scrollView.refreshControl) {
|
||||
return @[_contentView, _scrollView.refreshControl];
|
||||
}
|
||||
return _contentView ? @[_contentView] : @[];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user