From c53c9e821800454fcfd3c6b6c5dbb5b97a2cc482 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Fri, 13 Sep 2024 14:46:35 +0800 Subject: [PATCH] fix(ios): accuracy of ViewPager's onPageScroll event parameters fix(ios): improve accuracy of ViewPager's onPageScroll parameters --- .../component/viewPager/HippyViewPager.mm | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm b/renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm index e699ad605bd..c7932b49022 100644 --- a/renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm @@ -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 { @@ -197,14 +199,18 @@ - (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]; } } @@ -212,11 +218,17 @@ - (void)setPage:(NSInteger)pageNumber animated:(BOOL)animated { - (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]) { @@ -224,6 +236,8 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { } 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), @@ -237,7 +251,6 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { } } -//用户拖拽的开始,也是整个滚动流程的开始 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { self.isScrolling = YES; self.targetContentOffsetX = CGFLOAT_MAX; @@ -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 }); @@ -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 @@ -397,7 +414,7 @@ - (NSUInteger)pageIndexForContentOffset:(CGFloat)offset { - (void)setIsScrolling:(BOOL)isScrolling { if (!isScrolling) { - [self scrollViewDidEndScrolling]; + [self recordScrollStopOffsetX]; } _isScrolling = isScrolling; }