Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ios): fix viewpager onpagescroll and onpageselected event #761

Merged
merged 8 commits into from
May 19, 2021
105 changes: 65 additions & 40 deletions ios/sdk/component/viewPager/HippyViewPager.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ @interface HippyViewPager ()
@property (nonatomic, strong) NSMutableArray<UIView *> *viewPagerItems;
@property (nonatomic, assign) BOOL isScrolling;
@property (nonatomic, assign) BOOL loadOnce;
@property (nonatomic, assign) NSInteger pageOfBeginDragging;

@property (nonatomic, assign) CGRect previousFrame;
@property (nonatomic, assign) CGSize previousSize;
Expand All @@ -41,6 +40,9 @@ @interface HippyViewPager ()
@property (nonatomic, assign) BOOL needsLayoutItems;
@property (nonatomic, assign) BOOL needsResetPageIndex;

@property (nonatomic, assign) CGFloat previousStopOffset;
@property (nonatomic, assign) NSUInteger lastPageSelectedCallbackIndex;

@end

@implementation HippyViewPager
Expand Down Expand Up @@ -141,9 +143,7 @@ - (void)setPage:(NSInteger)pageNumber animated:(BOOL)animated {
UIView *theItem = self.viewPagerItems[pageNumber];
self.targetContentOffsetX = CGRectGetMinX(theItem.frame);
[self setContentOffset:theItem.frame.origin animated:animated];
if (self.onPageSelected) {
self.onPageSelected(@{ @"position": @(pageNumber) });
}
[self invokePageSelected:pageNumber];
if (self.onPageScrollStateChanged) {
self.onPageScrollStateChanged(@{ @"pageScrollState": @"idle" });
}
Expand All @@ -155,32 +155,34 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSString *state = scrollView.isDragging ? @"dragging" : @"settling";
self.onPageScrollStateChanged(@{ @"pageScrollState": state });
}
NSInteger beforePage = self.pageOfBeginDragging;
CGFloat commonPagerWidth = [self commonPagerWidth];
CGFloat beforeOffsetX = beforePage * commonPagerWidth;
CGFloat nowContentOffsetX = self.contentOffset.x;
CGFloat betweenOffset = nowContentOffsetX - beforeOffsetX;
CGFloat offsetRate = betweenOffset / commonPagerWidth;
if (offsetRate != 0) {
NSInteger nowPage = 0;
if (CGFLOAT_MAX == self.targetContentOffsetX) {
nowPage = offsetRate < 0 ? beforePage - 1 : beforePage + 1; //-1 for left slide,1 for right;
if (nowPage == -1) {
nowPage = 0;
}
if (nowPage == self.viewPagerItems.count) {
nowPage = self.viewPagerItems.count - 1;
}
} else {
nowPage = [self targetPageIndexFromTargetContentOffsetX:self.targetContentOffsetX];
}
if (self.onPageScroll) {
self.onPageScroll(@{
@"position": @(nowPage),
@"offset": @(offsetRate),
});
}

CGFloat currentContentOffset = self.contentOffset.x;
CGFloat offset = currentContentOffset - self.previousStopOffset;
CGFloat offsetRatio = offset / CGRectGetWidth(self.bounds);

if (offsetRatio > 1) {
offsetRatio -= floor(offsetRatio);
}
if (offsetRatio < -1) {
offsetRatio -= ceil(offsetRatio);
}

NSUInteger currentPageIndex = [self currentPageIndex];
NSInteger nextPageIndex = ceil(offsetRatio) == offsetRatio ? currentPageIndex : currentPageIndex + ceil(offsetRatio);
if (nextPageIndex < 0) {
nextPageIndex = 0;
}
if (nextPageIndex >= [self.viewPagerItems count]) {
nextPageIndex = [self.viewPagerItems count] - 1;
}

if (self.onPageScroll) {
self.onPageScroll(@{
@"position": @(nextPageIndex),
@"offset": @(offsetRatio),
});
}

for (NSObject<UIScrollViewDelegate> *scrollViewListener in _scrollViewListener) {
if ([scrollViewListener respondsToSelector:@selector(scrollViewDidScroll:)]) {
[scrollViewListener scrollViewDidScroll:scrollView];
Expand All @@ -190,7 +192,6 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView {

//用户拖拽的开始,也是整个滚动流程的开始
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
self.pageOfBeginDragging = self.nowPage;
self.isScrolling = YES;
self.targetContentOffsetX = CGFLOAT_MAX;
for (NSObject<UIScrollViewDelegate> *scrollViewListener in _scrollViewListener) {
Expand All @@ -203,9 +204,7 @@ - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
self.targetContentOffsetX = targetContentOffset->x;
NSUInteger page = [self targetPageIndexFromTargetContentOffsetX:self.targetContentOffsetX];
if (self.onPageSelected) {
self.onPageSelected(@{ @"position": @(page) });
}
[self invokePageSelected:page];
for (NSObject<UIScrollViewDelegate> *scrollViewListener in _scrollViewListener) {
if ([scrollViewListener respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
[scrollViewListener scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
Expand All @@ -219,6 +218,9 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL
[scrollViewListener scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
}
}
if (!decelerate) {
self.isScrolling = NO;
}
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
Expand Down Expand Up @@ -257,6 +259,10 @@ - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
}
}

- (void)scrollViewDidEndScrolling {
self.previousStopOffset = [self contentOffset].x;
}

#pragma mark scrollview listener methods
- (void)addScrollListener:(id<UIScrollViewDelegate>)scrollListener {
[_scrollViewListener addObject:scrollListener];
Expand All @@ -267,6 +273,32 @@ - (void)removeScrollListener:(id<UIScrollViewDelegate>)scrollListener {
}

#pragma mark other methods
- (NSUInteger)currentPageIndex {
return [self pageIndexForContentOffset:self.contentOffset.x];
}

- (NSUInteger)pageIndexForContentOffset:(CGFloat)offset {
CGFloat pageWidth = CGRectGetWidth(self.bounds);
NSUInteger page = floor(offset / pageWidth);
return page;
}

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

- (void)invokePageSelected:(NSUInteger)index {
if (self.onPageSelected &&
self.lastPageSelectedCallbackIndex != index &&
index < [[self viewPagerItems] count]) {
self.lastPageSelectedCallbackIndex = index;
self.onPageSelected(@{ @"position": @(index)});
}
}

- (NSUInteger)targetPageIndexFromTargetContentOffsetX:(CGFloat)targetContentOffsetX {
NSInteger thePage = -1;
if (fabs(targetContentOffsetX) < FLT_EPSILON) {
Expand Down Expand Up @@ -308,13 +340,6 @@ - (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated {
[super setContentOffset:contentOffset animated:animated];
}

- (CGFloat)commonPagerWidth {
if ([self.viewPagerItems count] == 0) {
return self.frame.size.width;
}
return self.viewPagerItems[0].frame.size.width;
}

- (void)hippyBridgeDidFinishTransaction {
BOOL isFrameEqual = CGRectEqualToRect(self.frame, self.previousFrame);
BOOL isContentSizeEqual = CGSizeEqualToSize(self.contentSize, self.previousSize);
Expand Down
1 change: 1 addition & 0 deletions ios/sdk/component/viewPager/HippyViewPagerManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ - (UIView *)view {
HIPPY_EXPORT_VIEW_PROPERTY(onPageSelected, HippyDirectEventBlock)
HIPPY_EXPORT_VIEW_PROPERTY(onPageScroll, HippyDirectEventBlock)
HIPPY_EXPORT_VIEW_PROPERTY(onPageScrollStateChanged, HippyDirectEventBlock)
HIPPY_EXPORT_VIEW_PROPERTY(bounces, BOOL)

// clang-format off
HIPPY_EXPORT_METHOD(setPage:(nonnull NSNumber *)hippyTag
Expand Down