Fix for incorrect contentSize reported by RCTScrollView

This commit is contained in:
Nick Lockwood 2015-03-25 15:01:00 -07:00
parent cd81fee57c
commit 87e7067809
2 changed files with 36 additions and 29 deletions

View File

@ -22,19 +22,25 @@
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
/**
* If the `contentSize` is not provided, then the `contentSize` will
* automatically be determined by the size of the `RKScrollView` subview.
*
* The `RCTScrollView` may have at most one single subview. This will ensure
* that the scroll view's `contentSize` will be efficiently set to the size of
* the single subview's frame. That frame size will be determined somewhat
* efficiently since it will have already been computed by the off-main-thread
* layout system.
*/
@property (nonatomic, readonly) UIScrollView *scrollView;
@property (nonatomic, readonly) UIView *contentView;
/**
* If the `contentSize` is not specified (or is specified as {0, 0}, then the
* `contentSize` will automatically be determined by the size of the subview.
*/
@property (nonatomic, assign) CGSize contentSize;
/**
* The underlying scrollView (TODO: can we remove this?)
*/
@property (nonatomic, readonly) UIScrollView *scrollView;
@property (nonatomic, assign) UIEdgeInsets contentInset;
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
@property (nonatomic, assign) NSUInteger throttleScrollCallbackMS;

View File

@ -253,7 +253,6 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
@implementation RCTScrollView
{
RCTEventDispatcher *_eventDispatcher;
BOOL _contentSizeManuallySet;
RCTCustomScrollView *_scrollView;
UIView *_contentView;
NSTimeInterval _lastScrollDispatchTime;
@ -273,6 +272,7 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
_scrollView.delaysContentTouches = NO;
_automaticallyAdjustContentInsets = YES;
_contentInset = UIEdgeInsetsZero;
_contentSize = CGSizeZero;
_throttleScrollCallbackMS = 0;
_lastScrollDispatchTime = CACurrentMediaTime();
@ -319,16 +319,6 @@ CGFloat const ZINDEX_STICKY_HEADER = 50;
_scrollView.stickyHeaderIndices = headerIndices;
}
/**
* Once you set the `contentSize`, it's assumed to be managed by you forever
* and we'll never automatically compute the size for you.
*/
- (void)setContentSize:(CGSize)contentSize
{
_contentSize = contentSize;
_contentSizeManuallySet = YES;
}
- (void)dealloc
{
_scrollView.delegate = nil;
@ -556,31 +546,42 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, RCTScrollEventTypeMove)
return newOffset;
}
- (void)reactBridgeDidFinishTransaction
/**
* Once you set the `contentSize`, to a nonzero value, it is assumed to be
* managed by you, and we'll never automatically compute the size for you,
* unless you manually reset it back to {0, 0}
*/
- (CGSize)contentSize
{
if (_contentSizeManuallySet) {
_scrollView.contentSize = _contentSize;
if (!CGSizeEqualToSize(_contentSize, CGSizeZero)) {
return _contentSize;
} else if (!_contentView) {
_scrollView.contentSize = CGSizeZero;
return CGSizeZero;
} else {
CGSize singleSubviewSize = _contentView.frame.size;
CGPoint singleSubviewPosition = _contentView.frame.origin;
CGSize fittedSize = {
return (CGSize){
singleSubviewSize.width + singleSubviewPosition.x,
singleSubviewSize.height + singleSubviewPosition.y
};
if (!CGSizeEqualToSize(_scrollView.contentSize, fittedSize)) {
// When contentSize is set manually, ScrollView internals will reset contentOffset to 0,0. Since
// we potentially set contentSize whenever anything in the ScrollView updates, we workaround this
// issue by manually adjusting contentOffset whenever this happens
CGPoint newOffset = [self calculateOffsetForContentSize:fittedSize];
_scrollView.contentSize = fittedSize;
_scrollView.contentOffset = newOffset;
}
[_scrollView dockClosestSectionHeader];
}
}
- (void)reactBridgeDidFinishTransaction
{
CGSize contentSize = self.contentSize;
if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) {
// When contentSize is set manually, ScrollView internals will reset
// contentOffset to {0, 0}. Since we potentially set contentSize whenever
// anything in the ScrollView updates, we workaround this issue by manually
// adjusting contentOffset whenever this happens
CGPoint newOffset = [self calculateOffsetForContentSize:contentSize];
_scrollView.contentSize = contentSize;
_scrollView.contentOffset = newOffset;
}
[_scrollView dockClosestSectionHeader];
}
// Note: setting several properties of UIScrollView has the effect of
// resetting its contentOffset to {0, 0}. To prevent this, we generate
// setters here that will record the contentOffset beforehand, and