Skip to content

Commit

Permalink
fix(ios): accuracy of ViewPager's onPageScroll event parameters
Browse files Browse the repository at this point in the history
fix(ios): improve accuracy of ViewPager's onPageScroll parameters
  • Loading branch information
wwwcg committed Sep 13, 2024
1 parent b0c2543 commit c53c9e8
Showing 1 changed file with 31 additions and 14 deletions.
45 changes: 31 additions & 14 deletions renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,12 @@ - (void)removeHippySubview:(UIView *)subview {
}

- (void)hippySetFrame:(CGRect)frame {
[super hippySetFrame:frame];
self.needsLayoutItems = YES;
self.needsResetPageIndex = YES;
[self setNeedsLayout];
if (!HippyCGRectRoundInPixelNearlyEqual(self.bounds, frame)) {
[super hippySetFrame:frame];
self.needsLayoutItems = YES;
self.needsResetPageIndex = YES;
[self setNeedsLayout];
}
}

- (void)didUpdateHippySubviews {
Expand Down Expand Up @@ -197,33 +199,45 @@ - (void)setPage:(NSInteger)pageNumber animated:(BOOL)animated {
[self setContentOffset:theItem.frame.origin animated:animated];
[self invokePageSelected:pageNumber];

if (self.onPageScrollStateChanged) {
if (animated) {
if (animated) {
if (self.onPageScrollStateChanged) {
HippyLogTrace(@"[HippyViewPager] settling --- (setPage withAnimation)");
self.onPageScrollStateChanged(@{ HippyPageScrollStateKey: HippyPageScrollStateSettling });
} else {
}
} else {
if (self.onPageScrollStateChanged) {
HippyLogTrace(@"[HippyViewPager] idle ~~~~~~ (setPage withoutAnimation)");
self.onPageScrollStateChanged(@{ HippyPageScrollStateKey: HippyPageScrollStateIdle });
}
// Record stop offset for onPageScroll callback
[self recordScrollStopOffsetX];
}
}

#pragma mark scrollview delegate methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

CGFloat currentContentOffset = self.contentOffset.x;
CGFloat pageWidth = CGRectGetWidth(self.bounds);
CGFloat offset = currentContentOffset - self.previousStopOffset;
CGFloat offsetRatio = fmod((offset / CGRectGetWidth(self.bounds)), 1.0 + DBL_EPSILON);
CGFloat offsetRatio = fmod((offset / pageWidth), 1.0 + DBL_EPSILON);

// get current base page index
NSUInteger currentPageIndex = floor(currentContentOffset / pageWidth);

NSUInteger currentPageIndex = [self currentPageIndex];
NSInteger nextPageIndex = ceil(offsetRatio) == offsetRatio ? currentPageIndex : currentPageIndex + ceil(offsetRatio);
// If offsetRatio is 1.0, then currentPageIndex is nextPageIndex, else nextPageIndex add/subtract 1.
// The theoretical maximum gap is 2 DBL_EPSILON, take 10 to allow for some redundancy.
BOOL isRatioEqualTo1 = (fabs(ceil(offsetRatio) - offsetRatio) < 10 * DBL_EPSILON);
NSInteger nextPageIndex = isRatioEqualTo1 ? currentPageIndex : currentPageIndex + ceil(offsetRatio);
if (nextPageIndex < 0) {
nextPageIndex = 0;
} else if (nextPageIndex >= [self.viewPagerItems count]) {
nextPageIndex = [self.viewPagerItems count] - 1;
}

if (self.onPageScroll) {
HippyLogTrace(@"[HippyViewPager] CurrentPage:%ld NextPage:%ld Ratio:%f, %f-%f-%f",
currentPageIndex, nextPageIndex, offsetRatio, pageWidth, currentContentOffset, offset);
self.onPageScroll(@{
@"position": @(nextPageIndex),
@"offset": @(offsetRatio),
Expand All @@ -237,7 +251,6 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
}
}

//用户拖拽的开始,也是整个滚动流程的开始
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
self.isScrolling = YES;
self.targetContentOffsetX = CGFLOAT_MAX;
Expand Down Expand Up @@ -331,6 +344,7 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
self.isScrolling = NO;
if (self.onPageScrollStateChanged) {
HippyLogTrace(@"[HippyViewPager] idle ~~~~~~ (DidEndScrollingAnimation)");
self.onPageScrollStateChanged(@{ HippyPageScrollStateKey : HippyPageScrollStateIdle });
Expand All @@ -351,8 +365,11 @@ - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
}
}

- (void)scrollViewDidEndScrolling {
self.previousStopOffset = [self contentOffset].x;
- (void)recordScrollStopOffsetX {
// Delay a bit to avoid recording offset of unfinished state
dispatch_async(dispatch_get_main_queue(), ^{
self.previousStopOffset = [self contentOffset].x;
});
}

#pragma mark scrollview listener methods
Expand Down Expand Up @@ -397,7 +414,7 @@ - (NSUInteger)pageIndexForContentOffset:(CGFloat)offset {

- (void)setIsScrolling:(BOOL)isScrolling {
if (!isScrolling) {
[self scrollViewDidEndScrolling];
[self recordScrollStopOffsetX];
}
_isScrolling = isScrolling;
}
Expand Down

0 comments on commit c53c9e8

Please sign in to comment.