@@ -911,16 +911,16 @@ - (void)updateContentOffsetIfNeeded
911
911
}
912
912
}
913
913
914
- // maintainPositionAtOrBeyondIndex is used to allow seamless loading of content from both ends of
914
+ // maintainVisibleContentPosition is used to allow seamless loading of content from both ends of
915
915
// the scrollview without the visible content jumping in position.
916
- - (void )setMaintainPositionAtOrBeyondIndex : ( NSNumber *)maintainPositionAtOrBeyondIndex
916
+ - (void )setMaintainVisibleContentPosition : ( NSDictionary *)maintainVisibleContentPosition
917
917
{
918
- if (maintainPositionAtOrBeyondIndex ! = nil ) {
918
+ if (maintainVisibleContentPosition != nil && _maintainVisibleContentPosition = = nil ) {
919
919
[_eventDispatcher.bridge.uiManager.observerCoordinator addObserver: self ];
920
- } else {
920
+ } else if (maintainVisibleContentPosition == nil && _maintainVisibleContentPosition != nil ) {
921
921
[_eventDispatcher.bridge.uiManager.observerCoordinator removeObserver: self ];
922
922
}
923
- _maintainPositionAtOrBeyondIndex = maintainPositionAtOrBeyondIndex ;
923
+ _maintainVisibleContentPosition = maintainVisibleContentPosition ;
924
924
}
925
925
926
926
#pragma mark - RCTUIManagerObserver
@@ -930,7 +930,7 @@ - (void)uiManagerWillPerformMounting:(RCTUIManager *)manager
930
930
RCTAssertUIManagerQueue ();
931
931
[manager prependUIBlock: ^(RCTUIManager *uiManager, NSDictionary <NSNumber *, UIView *> *viewRegistry) {
932
932
BOOL horz = [self isHorizontal: self ->_scrollView];
933
- NSUInteger minIdx = [self ->_maintainPositionAtOrBeyondIndex integerValue ];
933
+ NSUInteger minIdx = [self ->_maintainVisibleContentPosition[ @" minIndexForVisible " ] integerValue ];
934
934
for (NSUInteger ii = minIdx; ii < self->_contentView .subviews .count ; ++ii) {
935
935
// Find the first entirely visible view. This must be done after we update the content offset
936
936
// or it will tend to grab rows that were made visible by the shift in position
@@ -946,9 +946,10 @@ - (void)uiManagerWillPerformMounting:(RCTUIManager *)manager
946
946
}
947
947
}];
948
948
[manager addUIBlock: ^(RCTUIManager *uiManager, NSDictionary <NSNumber *, UIView *> *viewRegistry) {
949
- if (self->_maintainPositionAtOrBeyondIndex == nil ) {
949
+ if (self->_maintainVisibleContentPosition == nil ) {
950
950
return ; // The prop might have changed in the previous UIBlocks, so need to abort here.
951
951
}
952
+ NSNumber *autoscrollThreshold = self->_maintainVisibleContentPosition [@" autoscrollToTopThreshold" ];
952
953
// TODO: detect and handle/ignore re-ordering
953
954
if ([self isHorizontal: self ->_scrollView]) {
954
955
CGFloat deltaX = self->_firstVisibleView .frame .origin .x - self->_prevFirstVisibleFrame .origin .x ;
@@ -957,15 +958,27 @@ - (void)uiManagerWillPerformMounting:(RCTUIManager *)manager
957
958
self->_scrollView .contentOffset .x + deltaX,
958
959
self->_scrollView .contentOffset .y
959
960
);
961
+ if (autoscrollThreshold != nil ) {
962
+ // If the offset WAS within the threshold of the start, animate to the start.
963
+ if (self->_scrollView .contentOffset .x - deltaX <= [autoscrollThreshold integerValue ]) {
964
+ [self scrollToOffset: CGPointMake (0 , self ->_scrollView.contentOffset.y) animated: YES ];
965
+ }
966
+ }
960
967
}
961
968
} else {
962
969
CGRect newFrame = self->_firstVisibleView .frame ;
963
970
CGFloat deltaY = newFrame.origin .y - self->_prevFirstVisibleFrame .origin .y ;
964
- if (ABS (deltaY) > 0.1 || deltaY != 0.0 ) {
971
+ if (ABS (deltaY) > 0.1 ) {
965
972
self->_scrollView .contentOffset = CGPointMake (
966
973
self->_scrollView .contentOffset .x ,
967
974
self->_scrollView .contentOffset .y + deltaY
968
975
);
976
+ if (autoscrollThreshold != nil ) {
977
+ // If the offset WAS within the threshold of the start, animate to the start.
978
+ if (self->_scrollView .contentOffset .y - deltaY <= [autoscrollThreshold integerValue ]) {
979
+ [self scrollToOffset: CGPointMake (self ->_scrollView.contentOffset.x, 0 ) animated: YES ];
980
+ }
981
+ }
969
982
}
970
983
}
971
984
}];
0 commit comments