Skip to content

Commit 6255d40

Browse files
committed
[RTL/Batching] Make ASDisplayShouldFetchBatchForScrollView aware of flipped CV layouts (#1985)
* [RTL/Batching] Make ASDisplayShouldFetchBatchForScrollView aware of flipped CV layouts UICollectionViewLayout has a property called `flipsHorizontallyInOppositeLayoutDirection`. If this is set to `YES` then a RTL collectionView’s contentOffset behaves like it does in LTR. In other words, the first item is at contentOffset 0. In this case, the existing logic for `ASDisplayShouldFetchBatchForScrollView` works in RTL. If you don’t override `flipsHorizontallyInOppositeLayoutDirection` to be `YES`, then it means that in RTL languages the first item in your collectionView will actually be at x offset `collectionView.contentSize.width - collectionView.frame.size.width`. As you scroll to the right, the content offset will decrease until you reach the end of the data at a content offset of 0,0. In this case, `ASDisplayShouldFetchBatchForScrollView` needs to know that you are in RTL and the layout is not flipped. It can then use the contentOffset as the `remainingDistance` to determine when to fetch. * fix indentation * assert that we are on main when accessing CV layout
1 parent 8870628 commit 6255d40

5 files changed

Lines changed: 99 additions & 38 deletions

File tree

Source/ASCollectionView.mm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1857,7 +1857,10 @@ - (void)_checkForBatchFetching
18571857

18581858
- (void)_beginBatchFetchingIfNeededWithContentOffset:(CGPoint)contentOffset velocity:(CGPoint)velocity
18591859
{
1860-
if (ASDisplayShouldFetchBatchForScrollView(self, self.scrollDirection, self.scrollableDirections, contentOffset, velocity)) {
1860+
// Since we are accessing self.collectionViewLayout, we should make sure we are on main
1861+
ASDisplayNodeAssertMainThread();
1862+
1863+
if (ASDisplayShouldFetchBatchForScrollView(self, self.scrollDirection, self.scrollableDirections, contentOffset, velocity, self.collectionViewLayout.flipsHorizontallyInOppositeLayoutDirection)) {
18611864
[self _beginBatchFetching];
18621865
}
18631866
}

Source/ASTableView.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1486,7 +1486,7 @@ - (void)_checkForBatchFetching
14861486

14871487
- (void)_beginBatchFetchingIfNeededWithContentOffset:(CGPoint)contentOffset velocity:(CGPoint)velocity
14881488
{
1489-
if (ASDisplayShouldFetchBatchForScrollView(self, self.scrollDirection, ASScrollDirectionVerticalDirections, contentOffset, velocity)) {
1489+
if (ASDisplayShouldFetchBatchForScrollView(self, self.scrollDirection, ASScrollDirectionVerticalDirections, contentOffset, velocity, NO)) {
14901490
[self _beginBatchFetching];
14911491
}
14921492
}

Source/Private/ASBatchFetching.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ NS_ASSUME_NONNULL_BEGIN
3434
@param scrollableDirections The possible scrolling directions of the scroll view.
3535
@param contentOffset The offset that the scrollview will scroll to.
3636
@param velocity The velocity of the scroll view (in points) at the moment the touch was released.
37+
@param flipsHorizontallyInOppositeLayoutDirection Whether or not this scroll view flips its layout automatically in RTL.
38+
See flipsHorizontallyInOppositeLayoutDirection in UICollectionViewLayout
3739
@return Whether or not the current state should proceed with batch fetching.
3840
*/
3941
ASDK_EXTERN BOOL ASDisplayShouldFetchBatchForScrollView(UIScrollView<ASBatchFetchingScrollView> *scrollView,
4042
ASScrollDirection scrollDirection,
4143
ASScrollDirection scrollableDirections,
4244
CGPoint contentOffset,
43-
CGPoint velocity);
45+
CGPoint velocity,
46+
BOOL flipsHorizontallyInOppositeLayoutDirection);
4447

4548

4649
/**
@@ -55,6 +58,8 @@ ASDK_EXTERN BOOL ASDisplayShouldFetchBatchForScrollView(UIScrollView<ASBatchFetc
5558
@param visible Whether the view is visible or not.
5659
@param velocity The velocity of the scroll view (in points) at the moment the touch was released.
5760
@param delegate The delegate to be consulted if needed.
61+
@param flipsHorizontallyInOppositeLayoutDirection Whether or not this scroll view flips its layout automatically in RTL.
62+
See flipsHorizontallyInOppositeLayoutDirection in UICollectionViewLayout
5863
@return Whether or not the current state should proceed with batch fetching.
5964
@discussion This method is broken into a category for unit testing purposes and should be used with the ASTableView and
6065
* ASCollectionView batch fetching API.
@@ -69,6 +74,7 @@ ASDK_EXTERN BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context,
6974
BOOL visible,
7075
BOOL shouldRenderRTLLayout,
7176
CGPoint velocity,
77+
BOOL flipsHorizontallyInOppositeLayoutDirection,
7278
_Nullable id<ASBatchFetchingDelegate> delegate);
7379

7480
NS_ASSUME_NONNULL_END

Source/Private/ASBatchFetching.mm

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ BOOL ASDisplayShouldFetchBatchForScrollView(UIScrollView<ASBatchFetchingScrollVi
1515
ASScrollDirection scrollDirection,
1616
ASScrollDirection scrollableDirections,
1717
CGPoint contentOffset,
18-
CGPoint velocity)
18+
CGPoint velocity,
19+
BOOL flipsHorizontallyInOppositeLayoutDirection)
1920
{
2021
// Don't fetch if the scroll view does not allow
2122
if (![scrollView canBatchFetch]) {
@@ -30,7 +31,7 @@ BOOL ASDisplayShouldFetchBatchForScrollView(UIScrollView<ASBatchFetchingScrollVi
3031
id<ASBatchFetchingDelegate> delegate = scrollView.batchFetchingDelegate;
3132
BOOL visible = (scrollView.window != nil);
3233
BOOL shouldRenderRTLLayout = [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:scrollView.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft;
33-
return ASDisplayShouldFetchBatchForContext(context, scrollDirection, scrollableDirections, bounds, contentSize, contentOffset, leadingScreens, visible, shouldRenderRTLLayout, velocity, delegate);
34+
return ASDisplayShouldFetchBatchForContext(context, scrollDirection, scrollableDirections, bounds, contentSize, contentOffset, leadingScreens, visible, shouldRenderRTLLayout, velocity, flipsHorizontallyInOppositeLayoutDirection, delegate);
3435
}
3536

3637
BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context,
@@ -43,6 +44,7 @@ BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context,
4344
BOOL visible,
4445
BOOL shouldRenderRTLLayout,
4546
CGPoint velocity,
47+
BOOL flipsHorizontallyInOppositeLayoutDirection,
4648
id<ASBatchFetchingDelegate> delegate)
4749
{
4850
// Do not allow fetching if a batch is already in-flight and hasn't been completed or cancelled
@@ -87,11 +89,11 @@ BOOL ASDisplayShouldFetchBatchForContext(ASBatchContext *context,
8789
}
8890

8991
CGFloat triggerDistance = viewLength * leadingScreens;
90-
CGFloat remainingDistance = contentLength - viewLength - offset;
91-
if (shouldRenderRTLLayout && ASScrollDirectionContainsHorizontalDirection(scrollableDirections)) {
92-
remainingDistance = offset;
92+
CGFloat remainingDistance = 0;
93+
if (!flipsHorizontallyInOppositeLayoutDirection && shouldRenderRTLLayout && ASScrollDirectionContainsHorizontalDirection(scrollableDirections)) {
94+
remainingDistance = offset;
9395
} else {
94-
remainingDistance = contentLength - viewLength - offset;
96+
remainingDistance = contentLength - viewLength - offset;
9597
}
9698
BOOL result = remainingDistance <= triggerDistance;
9799

0 commit comments

Comments
 (0)