...
|
...
|
@@ -8,20 +8,21 @@ |
|
|
#import "RCTScrollView.h"
|
|
|
|
|
|
#import <UIKit/UIKit.h>
|
|
|
#import "YH_ThemeManager.h"
|
|
|
#import "YH_ThemeButton.h"
|
|
|
#import "YH_SystemNotification.h"
|
|
|
|
|
|
#import <React/RCTConvert.h>
|
|
|
#import <React/RCTEventDispatcher.h>
|
|
|
#import <React/RCTLog.h>
|
|
|
#import <React/RCTRefreshControl.h>
|
|
|
#import <React/RCTUIManager.h>
|
|
|
#import <React/RCTUtils.h>
|
|
|
#import <React/UIView+Private.h>
|
|
|
#import <React/UIView+React.h>
|
|
|
#import <React/RCTUIManagerObserverCoordinator.h>
|
|
|
#import <React/RCTUIManagerUtils.h>
|
|
|
|
|
|
#import "RCTConvert.h"
|
|
|
#import "RCTEventDispatcher.h"
|
|
|
#import "RCTLog.h"
|
|
|
#import "RCTUIManager.h"
|
|
|
#import "RCTUIManagerObserverCoordinator.h"
|
|
|
#import "RCTUIManagerUtils.h"
|
|
|
#import "RCTUtils.h"
|
|
|
#import "UIView+Private.h"
|
|
|
#import "UIView+React.h"
|
|
|
|
|
|
#if !TARGET_OS_TV
|
|
|
#import "RCTRefreshControl.h"
|
|
|
#endif
|
|
|
|
|
|
@interface RCTScrollEvent : NSObject <RCTEvent>
|
|
|
|
...
|
...
|
@@ -154,15 +155,16 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) |
|
|
@interface RCTCustomScrollView : UIScrollView<UIGestureRecognizerDelegate>
|
|
|
|
|
|
@property (nonatomic, assign) BOOL centerContent;
|
|
|
#if !TARGET_OS_TV
|
|
|
@property (nonatomic, strong) UIView<RCTCustomRefreshContolProtocol> *customRefreshControl;
|
|
|
@property (nonatomic, assign) BOOL pinchGestureEnabled;
|
|
|
#endif
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
@implementation RCTCustomScrollView
|
|
|
{
|
|
|
__weak UIView *_dockedHeaderView;
|
|
|
}
|
|
|
|
|
|
- (instancetype)initWithFrame:(CGRect)frame
|
|
|
{
|
...
|
...
|
@@ -331,7 +333,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) |
|
|
}
|
|
|
}
|
|
|
|
|
|
#if !TARGET_OS_TV
|
|
|
- (void)setCustomRefreshControl:(UIView<RCTCustomRefreshContolProtocol> *)refreshControl
|
|
|
{
|
|
|
if (_customRefreshControl) {
|
...
|
...
|
@@ -354,8 +355,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) |
|
|
// in the setter gets overriden when the view loads.
|
|
|
self.pinchGestureRecognizer.enabled = _pinchGestureEnabled;
|
|
|
}
|
|
|
#endif //TARGET_OS_TV
|
|
|
|
|
|
@end
|
|
|
|
|
|
@interface RCTScrollView () <RCTUIManagerObserver>
|
...
|
...
|
@@ -415,6 +414,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) |
|
|
_scrollListeners = [NSHashTable weakObjectsHashTable];
|
|
|
|
|
|
[self addSubview:_scrollView];
|
|
|
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(themeSwitchNotificationHandle:) name:YHBThemeDidChangeNotification object:nil];
|
|
|
|
|
|
}
|
|
|
return self;
|
|
|
}
|
...
|
...
|
@@ -445,7 +450,6 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(UIView *view, |
|
|
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
|
|
|
{
|
|
|
[super insertReactSubview:view atIndex:atIndex];
|
|
|
#if !TARGET_OS_TV
|
|
|
if ([view conformsToProtocol:@protocol(RCTCustomRefreshContolProtocol)]) {
|
|
|
[_scrollView setCustomRefreshControl:(UIView<RCTCustomRefreshContolProtocol> *)view];
|
|
|
if (![view isKindOfClass:[UIRefreshControl class]]
|
...
|
...
|
@@ -453,7 +457,6 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(UIView *view, |
|
|
[self addScrollListener:(UIView<UIScrollViewDelegate> *)view];
|
|
|
}
|
|
|
} else
|
|
|
#endif
|
|
|
{
|
|
|
RCTAssert(_contentView == nil, @"RCTScrollView may only contain a single subview");
|
|
|
_contentView = view;
|
...
|
...
|
@@ -465,7 +468,6 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(UIView *view, |
|
|
- (void)removeReactSubview:(UIView *)subview
|
|
|
{
|
|
|
[super removeReactSubview:subview];
|
|
|
#if !TARGET_OS_TV
|
|
|
if ([subview conformsToProtocol:@protocol(RCTCustomRefreshContolProtocol)]) {
|
|
|
[_scrollView setCustomRefreshControl:nil];
|
|
|
if (![subview isKindOfClass:[UIRefreshControl class]]
|
...
|
...
|
@@ -473,7 +475,6 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(UIView *view, |
|
|
[self removeScrollListener:(UIView<UIScrollViewDelegate> *)subview];
|
|
|
}
|
|
|
} else
|
|
|
#endif
|
|
|
{
|
|
|
RCTAssert(_contentView == subview, @"Attempted to remove non-existent subview");
|
|
|
_contentView = nil;
|
...
|
...
|
@@ -512,6 +513,11 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(UIView *view, |
|
|
{
|
|
|
_scrollView.delegate = nil;
|
|
|
[_eventDispatcher.bridge.uiManager.observerCoordinator removeObserver:self];
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
|
|
}
|
|
|
|
|
|
- (void)layoutSubviews
|
...
|
...
|
@@ -520,13 +526,11 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(UIView *view, |
|
|
RCTAssert(self.subviews.count == 1, @"we should only have exactly one subview");
|
|
|
RCTAssert([self.subviews lastObject] == _scrollView, @"our only subview should be a scrollview");
|
|
|
|
|
|
#if !TARGET_OS_TV
|
|
|
// Adjust the refresh control frame if the scrollview layout changes.
|
|
|
UIView<RCTCustomRefreshContolProtocol> *refreshControl = _scrollView.customRefreshControl;
|
|
|
if (refreshControl && refreshControl.isRefreshing) {
|
|
|
refreshControl.frame = (CGRect){_scrollView.contentOffset, {_scrollView.frame.size.width, refreshControl.frame.size.height}};
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
[self updateClippedSubviews];
|
|
|
}
|
...
|
...
|
@@ -1104,10 +1108,8 @@ RCT_SET_AND_PRESERVE_OFFSET(setKeyboardDismissMode, keyboardDismissMode, UIScrol |
|
|
RCT_SET_AND_PRESERVE_OFFSET(setMaximumZoomScale, maximumZoomScale, CGFloat)
|
|
|
RCT_SET_AND_PRESERVE_OFFSET(setMinimumZoomScale, minimumZoomScale, CGFloat)
|
|
|
RCT_SET_AND_PRESERVE_OFFSET(setScrollEnabled, isScrollEnabled, BOOL)
|
|
|
#if !TARGET_OS_TV
|
|
|
RCT_SET_AND_PRESERVE_OFFSET(setPagingEnabled, isPagingEnabled, BOOL)
|
|
|
RCT_SET_AND_PRESERVE_OFFSET(setScrollsToTop, scrollsToTop, BOOL)
|
|
|
#endif
|
|
|
RCT_SET_AND_PRESERVE_OFFSET(setShowsHorizontalScrollIndicator, showsHorizontalScrollIndicator, BOOL)
|
|
|
RCT_SET_AND_PRESERVE_OFFSET(setShowsVerticalScrollIndicator, showsVerticalScrollIndicator, BOOL)
|
|
|
RCT_SET_AND_PRESERVE_OFFSET(setZoomScale, zoomScale, CGFloat);
|
...
|
...
|
@@ -1147,6 +1149,125 @@ RCT_SET_AND_PRESERVE_OFFSET(setScrollIndicatorInsets, scrollIndicatorInsets, UIE |
|
|
[_eventDispatcher sendEvent:scrollEvent];
|
|
|
}
|
|
|
|
|
|
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
- (void)startPullToRefresh
|
|
|
{
|
|
|
self.isOnPullToRefresh = YES;
|
|
|
[_scrollView.header beginRefreshing];
|
|
|
|
|
|
}
|
|
|
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
- (void)stopPullToRefresh
|
|
|
{
|
|
|
self.isOnPullToRefresh = NO;
|
|
|
[_scrollView.header endRefreshing];
|
|
|
if (_onFinishRefreshData) {
|
|
|
_onFinishRefreshData(nil);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
- (void)setEnablePullToRefresh:(BOOL)enablePullToRefresh
|
|
|
{
|
|
|
_enablePullToRefresh = enablePullToRefresh;
|
|
|
if (enablePullToRefresh) {
|
|
|
if (_scrollView.header == nil) {
|
|
|
[_scrollView addGifHeaderWithRefreshingTarget:self refreshingAction:@selector(refreshData)];
|
|
|
[self customRefreshHeaderView];
|
|
|
self.currentRefreshingState = NO;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
- (void)setIsOnPullToRefresh:(BOOL)isOnPullToRefresh
|
|
|
{
|
|
|
if (_currentRefreshingState != isOnPullToRefresh) {
|
|
|
_currentRefreshingState = isOnPullToRefresh;
|
|
|
if (isOnPullToRefresh) {
|
|
|
[_scrollView.header beginRefreshing];
|
|
|
|
|
|
} else {
|
|
|
[_scrollView.header endRefreshing];
|
|
|
if (_onFinishRefreshData) {
|
|
|
_onFinishRefreshData(nil);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
-(void)refreshData
|
|
|
{
|
|
|
_currentRefreshingState = _scrollView.header.isRefreshing;
|
|
|
if (_onRefreshData) {
|
|
|
_onRefreshData(nil);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
- (void)setRefreshHeaderImage
|
|
|
{
|
|
|
// 设置普通状态的动画图片
|
|
|
NSString *idleImageName = [NSString stringWithFormat:@"refresh_000"];
|
|
|
UIImage *idleImage = [[YH_ThemeManager shareInstance] getThemeImage:idleImageName];
|
|
|
[_scrollView.gifHeader setImages:@[idleImage] forState:MJRefreshHeaderStateIdle];
|
|
|
|
|
|
// 设置正在刷新状态的动画图片
|
|
|
NSMutableArray *refreshingImages = [NSMutableArray array];
|
|
|
for (NSUInteger i = 1; i <= 12; i++) {
|
|
|
NSString *imageName = [NSString stringWithFormat:@"refresh_%03zd",i];
|
|
|
UIImage *image = [[YH_ThemeManager shareInstance] getThemeImage:imageName];
|
|
|
[refreshingImages addObject:image];
|
|
|
}
|
|
|
[_scrollView.gifHeader setImages:refreshingImages forState:MJRefreshHeaderStateRefreshing];
|
|
|
}
|
|
|
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
- (void)customRefreshHeaderView
|
|
|
{
|
|
|
// 隐藏时间
|
|
|
_scrollView.header.updatedTimeHidden = YES;
|
|
|
// 隐藏状态
|
|
|
_scrollView.header.stateHidden = YES;
|
|
|
|
|
|
[self setRefreshHeaderImage];
|
|
|
|
|
|
}
|
|
|
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
- (void)themeSwitchNotificationHandle:(NSNotification *)notification
|
|
|
{
|
|
|
if (_scrollView.header.isRefreshing) {
|
|
|
[_scrollView.header endRefreshing];
|
|
|
if (_onFinishRefreshData) {
|
|
|
_onFinishRefreshData(nil);
|
|
|
}
|
|
|
}
|
|
|
[self setRefreshHeaderImage];
|
|
|
}
|
|
|
// ********************
|
|
|
// add pull to refresh
|
|
|
// ********************
|
|
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
@implementation RCTEventDispatcher (RCTScrollView)
|
...
|
...
|
|