Fix for incorrect contentSize reported by RCTScrollView
This commit is contained in:
parent
cd81fee57c
commit
87e7067809
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue