Skip to content

Commit

Permalink
Remove unused native iOS sticky headers implementation
Browse files Browse the repository at this point in the history
Summary:
Remove the native iOS sticky headers implementation that has been replaced by the js Animated one. Also remove a line in JS that made sure we passed null to native so it did not use the native implementation.

**Test plan**
Made sure there were no more mentions of sticky / header in native ScrollView related code.
Tested that sticky headers still work :o
Closes facebook#12696

Differential Revision: D4657391

Pulled By: ericvicenti

fbshipit-source-id: 16324a45ca4ce5cd143293c61394a0fa7ad0c4a1
  • Loading branch information
janicduplessis authored and dojiboy9 committed Mar 18, 2017
1 parent 9bee799 commit b82ea9d
Show file tree
Hide file tree
Showing 4 changed files with 1 addition and 136 deletions.
1 change: 0 additions & 1 deletion Libraries/Components/ScrollView/ScrollView.js
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,6 @@ const ScrollView = React.createClass({
scrollEventThrottle: hasStickyHeaders ? 1 : this.props.scrollEventThrottle,
sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ?
true : false,
stickyHeaderIndices: null,
};

const { decelerationRate } = this.props;
Expand Down
1 change: 0 additions & 1 deletion React/Views/RCTScrollView.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
@property (nonatomic, assign) BOOL centerContent;
@property (nonatomic, assign) int snapToInterval;
@property (nonatomic, copy) NSString *snapToAlignment;
@property (nonatomic, copy) NSIndexSet *stickyHeaderIndices;

// NOTE: currently these event props are only declared so we can export the
// event names to JS - we don't call the blocks directly because scroll events
Expand Down
134 changes: 1 addition & 133 deletions React/Views/RCTScrollView.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
#import "RCTRefreshControl.h"
#endif

CGFloat const ZINDEX_DEFAULT = 0;
CGFloat const ZINDEX_STICKY_HEADER = 50;

@interface RCTScrollEvent : NSObject <RCTEvent>

- (instancetype)initWithEventName:(NSString *)eventName
Expand Down Expand Up @@ -137,11 +134,10 @@ - (NSArray *)arguments
/**
* Include a custom scroll view subclass because we want to limit certain
* default UIKit behaviors such as textFields automatically scrolling
* scroll views that contain them and support sticky headers.
* scroll views that contain them.
*/
@interface RCTCustomScrollView : UIScrollView<UIGestureRecognizerDelegate>

@property (nonatomic, copy) NSIndexSet *stickyHeaderIndices;
@property (nonatomic, assign) BOOL centerContent;
#if !TARGET_OS_TV
@property (nonatomic, strong) RCTRefreshControl *rctRefreshControl;
Expand All @@ -151,9 +147,6 @@ @interface RCTCustomScrollView : UIScrollView<UIGestureRecognizerDelegate>


@implementation RCTCustomScrollView
{
__weak UIView *_dockedHeaderView;
}

- (instancetype)initWithFrame:(CGRect)frame
{
Expand Down Expand Up @@ -279,98 +272,6 @@ - (void)setContentOffset:(CGPoint)contentOffset
super.contentOffset = contentOffset;
}

- (void)dockClosestSectionHeader
{
UIView *contentView = [self contentView];
CGFloat scrollTop = self.bounds.origin.y + self.contentInset.top;

#if !TARGET_OS_TV
// If the RefreshControl is refreshing, remove it's height so sticky headers are
// positioned properly when scrolling down while refreshing.
if (_rctRefreshControl != nil && _rctRefreshControl.refreshing) {
scrollTop -= _rctRefreshControl.frame.size.height;
}
#endif

// Find the section headers that need to be docked
__block UIView *previousHeader = nil;
__block UIView *currentHeader = nil;
__block UIView *nextHeader = nil;
NSUInteger subviewCount = contentView.reactSubviews.count;
[_stickyHeaderIndices enumerateIndexesWithOptions:0 usingBlock:
^(NSUInteger idx, BOOL *stop) {

// If the subviews are out of sync with the sticky header indices don't
// do anything.
if (idx >= subviewCount) {
*stop = YES;
return;
}

UIView *header = contentView.reactSubviews[idx];

// If nextHeader not yet found, search for docked headers
if (!nextHeader) {
CGFloat height = header.bounds.size.height;
CGFloat top = header.center.y - height * header.layer.anchorPoint.y;
if (top > scrollTop) {
nextHeader = header;
} else {
previousHeader = currentHeader;
currentHeader = header;
}
}

// Reset transforms for header views
header.transform = CGAffineTransformIdentity;
header.layer.zPosition = ZINDEX_DEFAULT;

}];

// If no docked header, bail out
if (!currentHeader) {
return;
}

// Adjust current header to hug the top of the screen
CGFloat currentFrameHeight = currentHeader.bounds.size.height;
CGFloat currentFrameTop = currentHeader.center.y - currentFrameHeight * currentHeader.layer.anchorPoint.y;
CGFloat yOffset = scrollTop - currentFrameTop;
if (nextHeader) {
// The next header nudges the current header out of the way when it reaches
// the top of the screen
CGFloat nextFrameHeight = nextHeader.bounds.size.height;
CGFloat nextFrameTop = nextHeader.center.y - nextFrameHeight * nextHeader.layer.anchorPoint.y;
CGFloat overlap = currentFrameHeight - (nextFrameTop - scrollTop);
yOffset -= MAX(0, overlap);
}
currentHeader.transform = CGAffineTransformMakeTranslation(0, yOffset);
currentHeader.layer.zPosition = ZINDEX_STICKY_HEADER;
_dockedHeaderView = currentHeader;

if (previousHeader) {
// The previous header sits right above the currentHeader's initial position
// so it scrolls away nicely once the currentHeader has locked into place
CGFloat previousFrameHeight = previousHeader.bounds.size.height;
CGFloat targetCenter = currentFrameTop - previousFrameHeight * (1.0 - previousHeader.layer.anchorPoint.y);
yOffset = targetCenter - previousHeader.center.y;
previousHeader.transform = CGAffineTransformMakeTranslation(0, yOffset);
previousHeader.layer.zPosition = ZINDEX_STICKY_HEADER;
}
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (_dockedHeaderView && [self pointInside:point withEvent:event]) {
CGPoint convertedPoint = [_dockedHeaderView convertPoint:point fromView:self];
UIView *hitView = [_dockedHeaderView hitTest:convertedPoint withEvent:event];
if (hitView) {
return hitView;
}
}
return [super hitTest:point withEvent:event];
}

static inline BOOL isRectInvalid(CGRect rect) {
return isnan(rect.origin.x) || isinf(rect.origin.x) ||
isnan(rect.origin.y) || isinf(rect.origin.y) ||
Expand Down Expand Up @@ -522,18 +423,6 @@ - (void)setCenterContent:(BOOL)centerContent
_scrollView.centerContent = centerContent;
}

- (NSIndexSet *)stickyHeaderIndices
{
return _scrollView.stickyHeaderIndices;
}

- (void)setStickyHeaderIndices:(NSIndexSet *)headerIndices
{
RCTAssert(_scrollView.contentSize.width <= self.frame.size.width,
@"sticky headers are not supported with horizontal scrolled views");
_scrollView.stickyHeaderIndices = headerIndices;
}

- (void)setClipsToBounds:(BOOL)clipsToBounds
{
super.clipsToBounds = clipsToBounds;
Expand Down Expand Up @@ -697,7 +586,6 @@ - (void)removeScrollListener:(NSObject<UIScrollViewDelegate> *)scrollListener

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[_scrollView dockClosestSectionHeader];
[self updateClippedSubviews];

NSTimeInterval now = CACurrentMediaTime();
Expand Down Expand Up @@ -960,26 +848,6 @@ - (void)reactBridgeDidFinishTransaction
_scrollView.contentSize = contentSize;
_scrollView.contentOffset = newOffset;
}

if (RCT_DEBUG) {
// Validate that sticky headers are not out of range.
NSUInteger subviewCount = _scrollView.contentView.reactSubviews.count;
NSUInteger lastIndex = NSNotFound;
if (_scrollView.stickyHeaderIndices != nil) {
lastIndex = _scrollView.stickyHeaderIndices.lastIndex;
}
if (lastIndex != NSNotFound && lastIndex >= subviewCount) {
RCTLogWarn(@"Sticky header index %zd was outside the range {0, %zd}",
lastIndex, subviewCount);
}
}
}

- (void)didSetProps:(NSArray<NSString *> *)changedProps
{
if ([changedProps containsObject:@"stickyHeaderIndices"]) {
[_scrollView dockClosestSectionHeader];
}
}

// Note: setting several properties of UIScrollView has the effect of
Expand Down
1 change: 0 additions & 1 deletion React/Views/RCTScrollViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ - (UIView *)view
#endif
RCT_EXPORT_VIEW_PROPERTY(showsHorizontalScrollIndicator, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL)
RCT_EXPORT_VIEW_PROPERTY(stickyHeaderIndices, NSIndexSet)
RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
Expand Down

0 comments on commit b82ea9d

Please sign in to comment.