From 5862cf5902c3e109b3f90099d78e62d66fe4e4cd Mon Sep 17 00:00:00 2001 From: arvinwli Date: Mon, 30 Oct 2023 20:16:53 +0800 Subject: [PATCH 01/13] feat(renderer): support scrollEventThrottle on Android and iOS --- .../src/components/ViewPager/index.jsx | 1 + .../hippy/views/viewpager/HippyViewPager.java | 7 ++++ .../viewpager/HippyViewPagerController.java | 4 +++ .../ViewPagerPageChangeListener.java | 20 +++++++++++- .../viewPager/NativeRenderViewPager.h | 2 ++ .../viewPager/NativeRenderViewPager.mm | 32 +++++++++++++++---- .../viewPager/NativeRenderViewPagerManager.mm | 1 + 7 files changed, 59 insertions(+), 8 deletions(-) diff --git a/driver/js/examples/hippy-react-demo/src/components/ViewPager/index.jsx b/driver/js/examples/hippy-react-demo/src/components/ViewPager/index.jsx index affccccf92a..43b9c2672fc 100644 --- a/driver/js/examples/hippy-react-demo/src/components/ViewPager/index.jsx +++ b/driver/js/examples/hippy-react-demo/src/components/ViewPager/index.jsx @@ -109,6 +109,7 @@ export default class PagerExample extends React.Component { onPageSelected={this.onPageSelected} onPageScrollStateChanged={this.onPageScrollStateChanged} onPageScroll={this.onPageScroll} + scrollEventThrottle={1000} > { [ diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java index e979903229a..edd53230a1b 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java @@ -69,6 +69,9 @@ public void run() { private final int[] mScrollOffsetPair = new int[2]; private int mNestedScrollOffset = 0; + protected int mScrollEventThrottle = 0; + + private void init(Context context, boolean isVertical) { setCallPageChangedOnFirstLayout(true); setEnableReLayoutOnAttachToWindow(false); @@ -328,6 +331,10 @@ public void setOverflow(String overflow) { invalidate(); } + public void setScrollEventThrottle(int scrollEventThrottle) { + mScrollEventThrottle = scrollEventThrottle; + } + @Override public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes) { if (!isScrollEnabled()) { diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java index 06493a63a8e..4a6dfbf63da 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java @@ -132,6 +132,10 @@ public void setOverflow(HippyViewPager pager, String overflow) { pager.setOverflow(overflow); } + @HippyControllerProps(name = "scrollEventThrottle", defaultType = HippyControllerProps.NUMBER, defaultNumber = 30.0D) + public void setScrollEventThrottle(HippyViewPager pager,int scrollEventThrottle) { + pager.setScrollEventThrottle(scrollEventThrottle); + } private void resolveInvalidParams(@Nullable Promise promise) { if (promise != null) { String msg = "Invalid parameter!"; diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java index f56d5d154a8..1320d8ba193 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java @@ -16,6 +16,7 @@ package com.tencent.mtt.hippy.views.viewpager; +import android.os.SystemClock; import android.view.View; import androidx.annotation.NonNull; @@ -34,14 +35,30 @@ public class ViewPagerPageChangeListener implements ViewPager.OnPageChangeListen private int mLastPageIndex = 0; private int mCurrPageIndex = 0; private final HippyViewPager mPager; + private long mLastScrollEventTimeStamp = -1; public ViewPagerPageChangeListener(@NonNull HippyViewPager pager) { mPager = pager; } + /** + * 检查是否需要发送事件 + * @return + */ + protected boolean checkSendOnScrollEvent() { + if (mPager.isScrollEnabled()) { + long currTime = SystemClock.elapsedRealtime(); + if (currTime - mLastScrollEventTimeStamp >= mPager.mScrollEventThrottle) { + mLastScrollEventTimeStamp = currTime; + return true; + } + } + return false; + } + @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - if (mPager != null) { + if (mPager != null && checkSendOnScrollEvent()) { Map params = new HashMap<>(); params.put(PAGE_ITEM_POSITION, position); params.put(PAGE_ITEM_OFFSET, positionOffset); @@ -91,6 +108,7 @@ private void onScrollStateChangeToIdle() { params.put(PAGE_ITEM_POSITION, mLastPageIndex); EventUtils.sendComponentEvent(lastView, EventUtils.EVENT_PAGE_ITEM_DID_DISAPPEAR, params); mLastPageIndex = mCurrPageIndex; + mLastScrollEventTimeStamp = -1; } @Override diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h index fd3a6a1f670..b7e1128758f 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h @@ -37,6 +37,8 @@ typedef void (^ViewPagerItemsCountChanged)(NSUInteger count); @property (nonatomic, strong) HippyDirectEventBlock onPageScrollStateChanged; @property (nonatomic, assign) NSInteger initialPage; +/// 滑动事件防抖 +@property (nonatomic, assign) double scrollEventThrottle; @property (nonatomic, assign) CGPoint targetOffset; @property (nonatomic, assign, readonly) NSUInteger pageCount; @property (nonatomic, copy) ViewPagerItemsCountChanged itemsChangedBlock; diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm index 23c3daf3999..40805ec4caa 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm @@ -45,7 +45,8 @@ @interface NativeRenderViewPager () @property (nonatomic, assign) CGFloat previousStopOffset; @property (nonatomic, assign) NSUInteger lastPageSelectedCallbackIndex; - +///用于滑动事件防抖 +@property (nonatomic, assign) double _lastScrollDispatchTime; @end @implementation NativeRenderViewPager @@ -62,6 +63,8 @@ - (instancetype)initWithFrame:(CGRect)frame { self.previousFrame = CGRectZero; self.scrollViewListener = [NSHashTable weakObjectsHashTable]; self.lastPageIndex = NSUIntegerMax; + self.scrollEventThrottle = 0.0; + self._lastScrollDispatchTime = -1; self.targetContentOffsetX = CGFLOAT_MAX; if (@available(iOS 11.0, *)) { self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; @@ -99,7 +102,7 @@ - (void)insertHippySubview:(UIView *)view atIndex:(NSInteger)atIndex { } [super insertHippySubview:view atIndex:(NSInteger)atIndex]; [self.viewPagerItems insertObject:view atIndex:atIndex]; - + if ([view isKindOfClass:[NativeRenderViewPagerItem class]]) { NativeRenderViewPagerItem *item = (NativeRenderViewPagerItem *)view; __weak NativeRenderViewPager *weakPager = self; @@ -117,7 +120,7 @@ - (void)insertHippySubview:(UIView *)view atIndex:(NSInteger)atIndex { return frame; }; } - + self.needsLayoutItems = YES; if (_itemsChangedBlock) { _itemsChangedBlock([self.viewPagerItems count]); @@ -175,14 +178,14 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 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) { @@ -191,14 +194,14 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (nextPageIndex >= [self.viewPagerItems count]) { nextPageIndex = [self.viewPagerItems count] - 1; } - + if (self.onPageScroll) { self.onPageScroll(@{ @"position": @(nextPageIndex), @"offset": @(offsetRatio), }); } - + for (NSObject *scrollViewListener in _scrollViewListener) { if ([scrollViewListener respondsToSelector:@selector(scrollViewDidScroll:)]) { [scrollViewListener scrollViewDidScroll:scrollView]; @@ -258,6 +261,8 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (self.onPageScrollStateChanged) { self.onPageScrollStateChanged(@{ @"pageScrollState": @"idle" }); } + //停止滚动后重置时间 + self._lastScrollDispatchTime = -1; self.isScrolling = NO; for (NSObject *scrollViewListener in _scrollViewListener) { if ([scrollViewListener respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) { @@ -490,4 +495,17 @@ - (void)autoPageDown { } } +/**判断是否需要发送 OnScroll事件*/ +- (bool)checkSendOnScrollEvent { + if (!self.scrollEnabled) { + return false; + } + NSTimeInterval now = CACurrentMediaTime(); + if ((self.scrollEventThrottle > 0 && self.scrollEventThrottle < (now - self._lastScrollDispatchTime) * 1000)) { + self._lastScrollDispatchTime = now; + return true; + } + return false; +} + @end diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPagerManager.mm b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPagerManager.mm index 95a18448dbc..fd650d714e9 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPagerManager.mm +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPagerManager.mm @@ -35,6 +35,7 @@ - (UIView *)view { HIPPY_EXPORT_VIEW_PROPERTY(bounces, BOOL) HIPPY_EXPORT_VIEW_PROPERTY(initialPage, NSInteger) HIPPY_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL) +HIPPY_EXPORT_VIEW_PROPERTY(scrollEventThrottle, double) HIPPY_EXPORT_VIEW_PROPERTY(onPageSelected, HippyDirectEventBlock) HIPPY_EXPORT_VIEW_PROPERTY(onPageScroll, HippyDirectEventBlock) From 46381ffe16c576e6305a7b1b420786dea3d027ea Mon Sep 17 00:00:00 2001 From: arvinwli Date: Tue, 31 Oct 2023 16:37:11 +0800 Subject: [PATCH 02/13] feat(renderer): cr fix --- .../com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java | 3 +-- .../mtt/hippy/views/viewpager/HippyViewPagerController.java | 3 ++- .../mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java index edd53230a1b..34d891e9983 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java @@ -68,10 +68,9 @@ public void run() { // Reusable int array to be passed to method calls that mutate it in order to "return" two ints. private final int[] mScrollOffsetPair = new int[2]; private int mNestedScrollOffset = 0; - + //防抖时间 ms protected int mScrollEventThrottle = 0; - private void init(Context context, boolean isVertical) { setCallPageChangedOnFirstLayout(true); setEnableReLayoutOnAttachToWindow(false); diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java index 4a6dfbf63da..f386e149cac 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPagerController.java @@ -132,10 +132,11 @@ public void setOverflow(HippyViewPager pager, String overflow) { pager.setOverflow(overflow); } - @HippyControllerProps(name = "scrollEventThrottle", defaultType = HippyControllerProps.NUMBER, defaultNumber = 30.0D) + @HippyControllerProps(name = "scrollEventThrottle", defaultType = HippyControllerProps.NUMBER, defaultNumber = 0) public void setScrollEventThrottle(HippyViewPager pager,int scrollEventThrottle) { pager.setScrollEventThrottle(scrollEventThrottle); } + private void resolveInvalidParams(@Nullable Promise promise) { if (promise != null) { String msg = "Invalid parameter!"; diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java index 1320d8ba193..11dee4dd355 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java @@ -108,6 +108,8 @@ private void onScrollStateChangeToIdle() { params.put(PAGE_ITEM_POSITION, mLastPageIndex); EventUtils.sendComponentEvent(lastView, EventUtils.EVENT_PAGE_ITEM_DID_DISAPPEAR, params); mLastPageIndex = mCurrPageIndex; + //防抖只是针对onScroll事件。 状态事件不参与过滤,也不会被丢弃。 + // 状态变成idle只是重置mLastScrollEventTimeStamp,以便下次滑动开始时,重新计算。 mLastScrollEventTimeStamp = -1; } From 31c9f0f5dde8da33e2d90ee84397ea7fd4c5bc63 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Tue, 31 Oct 2023 19:18:07 +0800 Subject: [PATCH 03/13] feat(renderer): cr fix --- .../hippy/views/viewpager/HippyViewPager.java | 2 +- .../ViewPagerPageChangeListener.java | 35 ++++++++++++++----- .../viewPager/NativeRenderViewPager.h | 1 - .../viewPager/NativeRenderViewPager.mm | 3 +- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java index 34d891e9983..e6fbde04a49 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/HippyViewPager.java @@ -68,7 +68,7 @@ public void run() { // Reusable int array to be passed to method calls that mutate it in order to "return" two ints. private final int[] mScrollOffsetPair = new int[2]; private int mNestedScrollOffset = 0; - //防抖时间 ms + //scroll throttle time ms protected int mScrollEventThrottle = 0; private void init(Context context, boolean isVertical) { diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java index 11dee4dd355..85c76422696 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java @@ -36,13 +36,16 @@ public class ViewPagerPageChangeListener implements ViewPager.OnPageChangeListen private int mCurrPageIndex = 0; private final HippyViewPager mPager; private long mLastScrollEventTimeStamp = -1; + private boolean mHasUnsentScrollEvent; + private int onPageScrolledPosition = 0; + private float onPageScrollPositionOffset = 0; public ViewPagerPageChangeListener(@NonNull HippyViewPager pager) { mPager = pager; } /** - * 检查是否需要发送事件 + * Check whether scroll events need to be sent * @return */ protected boolean checkSendOnScrollEvent() { @@ -58,14 +61,26 @@ protected boolean checkSendOnScrollEvent() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - if (mPager != null && checkSendOnScrollEvent()) { - Map params = new HashMap<>(); - params.put(PAGE_ITEM_POSITION, position); - params.put(PAGE_ITEM_OFFSET, positionOffset); - EventUtils.sendComponentEvent(mPager, EventUtils.EVENT_PAGE_SCROLL, params); + onPageScrolledPosition = position; + onPageScrollPositionOffset = positionOffset; + if (mPager == null) { + return; + } + if (checkSendOnScrollEvent()) { + sendPageScrollEvent(position, positionOffset); + } else { + mHasUnsentScrollEvent = true; } } + private void sendPageScrollEvent(int position, float positionOffset) { + mHasUnsentScrollEvent = false; + Map params = new HashMap<>(); + params.put(PAGE_ITEM_POSITION, position); + params.put(PAGE_ITEM_OFFSET, positionOffset); + EventUtils.sendComponentEvent(mPager, EventUtils.EVENT_PAGE_SCROLL, params); + } + @Override public void onPageSelected(int position) { if (mPager != null) { @@ -92,6 +107,11 @@ private void onScrollStateChangeToIdle() { if (mPager == null || mCurrPageIndex == mLastPageIndex) { return; } + mLastScrollEventTimeStamp = -1; + // Supplementary sending page scroll event + if (mHasUnsentScrollEvent) { + sendPageScrollEvent(onPageScrolledPosition, onPageScrollPositionOffset); + } Promise promise = mPager.getCallBackPromise(); if (promise != null) { Map result = new HashMap<>(); @@ -108,9 +128,6 @@ private void onScrollStateChangeToIdle() { params.put(PAGE_ITEM_POSITION, mLastPageIndex); EventUtils.sendComponentEvent(lastView, EventUtils.EVENT_PAGE_ITEM_DID_DISAPPEAR, params); mLastPageIndex = mCurrPageIndex; - //防抖只是针对onScroll事件。 状态事件不参与过滤,也不会被丢弃。 - // 状态变成idle只是重置mLastScrollEventTimeStamp,以便下次滑动开始时,重新计算。 - mLastScrollEventTimeStamp = -1; } @Override diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h index b7e1128758f..464e70e0ffa 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h @@ -37,7 +37,6 @@ typedef void (^ViewPagerItemsCountChanged)(NSUInteger count); @property (nonatomic, strong) HippyDirectEventBlock onPageScrollStateChanged; @property (nonatomic, assign) NSInteger initialPage; -/// 滑动事件防抖 @property (nonatomic, assign) double scrollEventThrottle; @property (nonatomic, assign) CGPoint targetOffset; @property (nonatomic, assign, readonly) NSUInteger pageCount; diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm index 40805ec4caa..e94f082af64 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm @@ -45,7 +45,6 @@ @interface NativeRenderViewPager () @property (nonatomic, assign) CGFloat previousStopOffset; @property (nonatomic, assign) NSUInteger lastPageSelectedCallbackIndex; -///用于滑动事件防抖 @property (nonatomic, assign) double _lastScrollDispatchTime; @end @@ -495,7 +494,7 @@ - (void)autoPageDown { } } -/**判断是否需要发送 OnScroll事件*/ +/**Check whether scroll events need to be sent*/ - (bool)checkSendOnScrollEvent { if (!self.scrollEnabled) { return false; From 0f4ef81a02a5e66be6ea2a9f8ac113b50254ea70 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Tue, 31 Oct 2023 19:39:52 +0800 Subject: [PATCH 04/13] feat(renderer): support iOS --- .../viewPager/NativeRenderViewPager.mm | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm index e94f082af64..42c9162b0f7 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm @@ -46,6 +46,9 @@ @interface NativeRenderViewPager () @property (nonatomic, assign) CGFloat previousStopOffset; @property (nonatomic, assign) NSUInteger lastPageSelectedCallbackIndex; @property (nonatomic, assign) double _lastScrollDispatchTime; +@property (nonatomic, assign) double mHasUnsentScrollEvent; +@property (nonatomic, assign) NSUInteger onPageScrolledPosition; +@property (nonatomic, assign) CGFloat onPageScrollPositionOffset; @end @implementation NativeRenderViewPager @@ -195,10 +198,18 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { } if (self.onPageScroll) { - self.onPageScroll(@{ - @"position": @(nextPageIndex), - @"offset": @(offsetRatio), - }); + if ([self checkSendOnScrollEvent]) { + self.mHasUnsentScrollEvent = false; + self.onPageScrolledPosition = nextPageIndex; + self.onPageScrollPositionOffset = offsetRatio; + self.onPageScroll(@{ + @"position": @(nextPageIndex), + @"offset": @(offsetRatio), + }); + } else { + self.mHasUnsentScrollEvent = true; + } + } for (NSObject *scrollViewListener in _scrollViewListener) { @@ -244,6 +255,9 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL } if (self.onPageScrollStateChanged) { NSString *state = decelerate ? @"settling" : @"idle"; + if(!decelerate) { + [self supplementaryPageScrollEvent]; + } self.onPageScrollStateChanged(@{ @"pageScrollState": state }); } } @@ -258,6 +272,7 @@ - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (self.onPageScrollStateChanged) { + [self supplementaryPageScrollEvent]; self.onPageScrollStateChanged(@{ @"pageScrollState": @"idle" }); } //停止滚动后重置时间 @@ -496,15 +511,21 @@ - (void)autoPageDown { /**Check whether scroll events need to be sent*/ - (bool)checkSendOnScrollEvent { - if (!self.scrollEnabled) { - return false; - } NSTimeInterval now = CACurrentMediaTime(); - if ((self.scrollEventThrottle > 0 && self.scrollEventThrottle < (now - self._lastScrollDispatchTime) * 1000)) { + if (self.scrollEventThrottle < (now - self._lastScrollDispatchTime) * 1000) { self._lastScrollDispatchTime = now; return true; } return false; } +- (void)supplementaryPageScrollEvent { + if(self.mHasUnsentScrollEvent) { + self.onPageScroll(@{ + @"position": @(self.onPageScrolledPosition), + @"offset": @(self.onPageScrollPositionOffset), + }); + } +} + @end From 5b6d14cc05a30ab5b5a79e69c20d169dbb457ff2 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Tue, 31 Oct 2023 19:44:24 +0800 Subject: [PATCH 05/13] feat(renderer): support android --- .../viewpager/ViewPagerPageChangeListener.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java index 85c76422696..b1af0e8ee5d 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java @@ -49,12 +49,10 @@ public ViewPagerPageChangeListener(@NonNull HippyViewPager pager) { * @return */ protected boolean checkSendOnScrollEvent() { - if (mPager.isScrollEnabled()) { - long currTime = SystemClock.elapsedRealtime(); - if (currTime - mLastScrollEventTimeStamp >= mPager.mScrollEventThrottle) { - mLastScrollEventTimeStamp = currTime; - return true; - } + long currTime = SystemClock.elapsedRealtime(); + if (currTime - mLastScrollEventTimeStamp >= mPager.mScrollEventThrottle) { + mLastScrollEventTimeStamp = currTime; + return true; } return false; } @@ -66,6 +64,9 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse if (mPager == null) { return; } + if (!mPager.isScrollEnabled()) { + return; + } if (checkSendOnScrollEvent()) { sendPageScrollEvent(position, positionOffset); } else { From 5a7d03e8da06c01033952863d9d313ac4b3b22e7 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Tue, 31 Oct 2023 19:54:02 +0800 Subject: [PATCH 06/13] feat(renderer): aligning iOS and android --- .../viewPager/NativeRenderViewPager.mm | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm index 42c9162b0f7..b436a552446 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm @@ -199,17 +199,13 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (self.onPageScroll) { if ([self checkSendOnScrollEvent]) { - self.mHasUnsentScrollEvent = false; self.onPageScrolledPosition = nextPageIndex; self.onPageScrollPositionOffset = offsetRatio; - self.onPageScroll(@{ - @"position": @(nextPageIndex), - @"offset": @(offsetRatio), - }); + [self sendOnPageScrollEvent:self.onPageScrolledPosition positionOffset:self.onPageScrollPositionOffset]; } else { self.mHasUnsentScrollEvent = true; } - + } for (NSObject *scrollViewListener in _scrollViewListener) { @@ -519,12 +515,18 @@ - (bool)checkSendOnScrollEvent { return false; } +- (void) sendOnPageScrollEvent: (NSUInteger)position positionOffset:(CGFloat) positionOffset{ + self.mHasUnsentScrollEvent = false; + self.onPageScroll(@{ + @"position": @(position), + @"offset": @(positionOffset), + }); +} + - (void)supplementaryPageScrollEvent { if(self.mHasUnsentScrollEvent) { - self.onPageScroll(@{ - @"position": @(self.onPageScrolledPosition), - @"offset": @(self.onPageScrollPositionOffset), - }); + self.mHasUnsentScrollEvent = false; + [self sendOnPageScrollEvent:self.onPageScrolledPosition positionOffset:self.onPageScrollPositionOffset]; } } From 97b0fd7a37e373197209eebfb3ce4f48851462f5 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Tue, 31 Oct 2023 20:00:47 +0800 Subject: [PATCH 07/13] feat(renderer): opt iOS onPageScroll --- .../component/viewPager/NativeRenderViewPager.mm | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm index b436a552446..c5e1fce0d9a 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm @@ -249,11 +249,12 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL if (!decelerate) { self.isScrolling = NO; } + + if(!decelerate) { + [self onScrollIdle]; + } if (self.onPageScrollStateChanged) { NSString *state = decelerate ? @"settling" : @"idle"; - if(!decelerate) { - [self supplementaryPageScrollEvent]; - } self.onPageScrollStateChanged(@{ @"pageScrollState": state }); } } @@ -267,12 +268,10 @@ - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + [self onScrollIdle]; if (self.onPageScrollStateChanged) { - [self supplementaryPageScrollEvent]; self.onPageScrollStateChanged(@{ @"pageScrollState": @"idle" }); } - //停止滚动后重置时间 - self._lastScrollDispatchTime = -1; self.isScrolling = NO; for (NSObject *scrollViewListener in _scrollViewListener) { if ([scrollViewListener respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) { @@ -523,7 +522,9 @@ - (void) sendOnPageScrollEvent: (NSUInteger)position positionOffset:(CGFloat) p }); } -- (void)supplementaryPageScrollEvent { +- (void)onScrollIdle { + //reset on scroll idle + self._lastScrollDispatchTime = -1; if(self.mHasUnsentScrollEvent) { self.mHasUnsentScrollEvent = false; [self sendOnPageScrollEvent:self.onPageScrolledPosition positionOffset:self.onPageScrollPositionOffset]; From dd7cb9ebaddacddb7d756df6d8aee018d214ab4e Mon Sep 17 00:00:00 2001 From: arvinwli Date: Tue, 31 Oct 2023 20:03:06 +0800 Subject: [PATCH 08/13] feat(renderer): opt iOS onPageScroll --- .../ios/renderer/component/viewPager/NativeRenderViewPager.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm index c5e1fce0d9a..1f28a40159c 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm @@ -514,7 +514,7 @@ - (bool)checkSendOnScrollEvent { return false; } -- (void) sendOnPageScrollEvent: (NSUInteger)position positionOffset:(CGFloat) positionOffset{ +- (void)sendOnPageScrollEvent: (NSUInteger)position positionOffset:(CGFloat) positionOffset{ self.mHasUnsentScrollEvent = false; self.onPageScroll(@{ @"position": @(position), From d614d852b419425914e3bfe717174d5a89ff34d4 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Wed, 1 Nov 2023 09:40:39 +0800 Subject: [PATCH 09/13] feat(renderer): replenishment doc --- docs/api/hippy-react/components.md | 1 + .../mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/api/hippy-react/components.md b/docs/api/hippy-react/components.md index ff3a957f12a..2801a24198a 100644 --- a/docs/api/hippy-react/components.md +++ b/docs/api/hippy-react/components.md @@ -482,6 +482,7 @@ import icon from './qb_icon_new.png'; | onPageScroll | 指定一个函数,当 page 被滑动时进行回调。回调参数是一个 event 对象,回调参数 `position: number` - 表示即将滑到的目标 page 的索引,`offset: number` - 当前被选中的 page 的相对位移,取值范围 -1 到 1 | `(obj: {position: number, offset: number}) => void` | `Android、iOS、Web-Renderer、Voltron` | | onPageScrollStateChanged | 指定一个函数,当 page 的滑动状态改变时进行回调。回调参数: `pageScrollState: string` - 改变后的状态,`idle` 表示停止,`dragging` 表示用户用手拖拽,`settling` 表示 page 正在滑动 | `(pageScrollState: string) => void` | `Android、iOS、hippy-react-web、Web-Renderer、Voltron` | | direction | 设置 viewPager 滚动方向,不设置默认横向滚动,设置 `vertical` 为竖向滚动 | `string` | `Android、hippy-react-web、Voltron` | +| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onPageScroll` 事件 | `number` | `Android、iOS、hippy-react-web、Web-Renderer、Voltron` | ## 方法 diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java index b1af0e8ee5d..8b8a2500cc5 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/views/viewpager/ViewPagerPageChangeListener.java @@ -48,7 +48,7 @@ public ViewPagerPageChangeListener(@NonNull HippyViewPager pager) { * Check whether scroll events need to be sent * @return */ - protected boolean checkSendOnScrollEvent() { + private boolean checkSendOnScrollEvent() { long currTime = SystemClock.elapsedRealtime(); if (currTime - mLastScrollEventTimeStamp >= mPager.mScrollEventThrottle) { mLastScrollEventTimeStamp = currTime; From f740a121f0f9b1e00e882626eb42a9d98dfe8dbf Mon Sep 17 00:00:00 2001 From: arvinwli Date: Wed, 1 Nov 2023 10:00:10 +0800 Subject: [PATCH 10/13] feat(renderer): replenishment example and doc --- docs/api/hippy-vue/external-components.md | 1 + .../hippy-vue-demo/src/components/native-demos/demo-swiper.vue | 1 + .../src/components/native-demo/demo-swiper.vue | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/api/hippy-vue/external-components.md b/docs/api/hippy-vue/external-components.md index 8c175c52baa..0c011e30cb7 100644 --- a/docs/api/hippy-vue/external-components.md +++ b/docs/api/hippy-vue/external-components.md @@ -190,6 +190,7 @@ export default { | needAnimation | 切换页面时是否需要动画。 | `boolean` | `Android、iOS、Voltron` | | scrollEnabled | 指定ViewPager是否可以滑动,默认为true | `boolean` | `Android、iOS、Web-Renderer、Voltron` | | direction | 设置viewPager滚动方向,不设置默认横向滚动,设置 `vertical` 为竖向滚动 | `string` | `Android、Voltron` | +| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onPageScroll` 事件 | `number` | `Android、iOS、Web-Renderer、Voltron` | ## 事件 diff --git a/driver/js/examples/hippy-vue-demo/src/components/native-demos/demo-swiper.vue b/driver/js/examples/hippy-vue-demo/src/components/native-demos/demo-swiper.vue index 06136f17940..633b0b87042 100644 --- a/driver/js/examples/hippy-vue-demo/src/components/native-demos/demo-swiper.vue +++ b/driver/js/examples/hippy-vue-demo/src/components/native-demos/demo-swiper.vue @@ -29,6 +29,7 @@ ref="swiper" need-animation :current="currentSlide" + :scrollEventThrottle="1000" @dragging="onDragging" @dropped="onDropped" @stateChanged="onStateChanged" diff --git a/driver/js/examples/hippy-vue-next-demo/src/components/native-demo/demo-swiper.vue b/driver/js/examples/hippy-vue-next-demo/src/components/native-demo/demo-swiper.vue index 7e59f62b589..c3d244e40f3 100644 --- a/driver/js/examples/hippy-vue-next-demo/src/components/native-demo/demo-swiper.vue +++ b/driver/js/examples/hippy-vue-next-demo/src/components/native-demo/demo-swiper.vue @@ -29,6 +29,7 @@ ref="swiper" need-animation :current="currentSlide" + :scrollEventThrottle="1000" @dragging="onDragging" @dropped="onDropped" @stateChanged="onStateChanged" From 038ddc0c3ee4ed8694c323dc19921d2cd6c76d50 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Wed, 1 Nov 2023 10:05:07 +0800 Subject: [PATCH 11/13] feat(renderer): replenishment example and doc --- docs/api/hippy-vue/external-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/hippy-vue/external-components.md b/docs/api/hippy-vue/external-components.md index 0c011e30cb7..14ef4c59d92 100644 --- a/docs/api/hippy-vue/external-components.md +++ b/docs/api/hippy-vue/external-components.md @@ -190,7 +190,7 @@ export default { | needAnimation | 切换页面时是否需要动画。 | `boolean` | `Android、iOS、Voltron` | | scrollEnabled | 指定ViewPager是否可以滑动,默认为true | `boolean` | `Android、iOS、Web-Renderer、Voltron` | | direction | 设置viewPager滚动方向,不设置默认横向滚动,设置 `vertical` 为竖向滚动 | `string` | `Android、Voltron` | -| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onPageScroll` 事件 | `number` | `Android、iOS、Web-Renderer、Voltron` | +| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onPageScroll` 事件 | `number` | `Android、iOS、Voltron` | ## 事件 From 12880a1f7ecafeecd122534b88d185435ff38ed2 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Wed, 1 Nov 2023 15:37:51 +0800 Subject: [PATCH 12/13] feat(renderer): fix api doc --- docs/api/hippy-react/components.md | 2 +- docs/api/hippy-vue/external-components.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/hippy-react/components.md b/docs/api/hippy-react/components.md index 2801a24198a..887f8602c1a 100644 --- a/docs/api/hippy-react/components.md +++ b/docs/api/hippy-react/components.md @@ -482,7 +482,7 @@ import icon from './qb_icon_new.png'; | onPageScroll | 指定一个函数,当 page 被滑动时进行回调。回调参数是一个 event 对象,回调参数 `position: number` - 表示即将滑到的目标 page 的索引,`offset: number` - 当前被选中的 page 的相对位移,取值范围 -1 到 1 | `(obj: {position: number, offset: number}) => void` | `Android、iOS、Web-Renderer、Voltron` | | onPageScrollStateChanged | 指定一个函数,当 page 的滑动状态改变时进行回调。回调参数: `pageScrollState: string` - 改变后的状态,`idle` 表示停止,`dragging` 表示用户用手拖拽,`settling` 表示 page 正在滑动 | `(pageScrollState: string) => void` | `Android、iOS、hippy-react-web、Web-Renderer、Voltron` | | direction | 设置 viewPager 滚动方向,不设置默认横向滚动,设置 `vertical` 为竖向滚动 | `string` | `Android、hippy-react-web、Voltron` | -| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onPageScroll` 事件 | `number` | `Android、iOS、hippy-react-web、Web-Renderer、Voltron` | +| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onPageScroll` 事件 | `number` | `Android、iOS` | ## 方法 diff --git a/docs/api/hippy-vue/external-components.md b/docs/api/hippy-vue/external-components.md index 14ef4c59d92..c8e4dc96acf 100644 --- a/docs/api/hippy-vue/external-components.md +++ b/docs/api/hippy-vue/external-components.md @@ -190,7 +190,7 @@ export default { | needAnimation | 切换页面时是否需要动画。 | `boolean` | `Android、iOS、Voltron` | | scrollEnabled | 指定ViewPager是否可以滑动,默认为true | `boolean` | `Android、iOS、Web-Renderer、Voltron` | | direction | 设置viewPager滚动方向,不设置默认横向滚动,设置 `vertical` 为竖向滚动 | `string` | `Android、Voltron` | -| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onPageScroll` 事件 | `number` | `Android、iOS、Voltron` | +| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onPageScroll` 事件 | `number` | `Android、iOS` | ## 事件 From 9d65d5ef12458d1b99629742bff070fdafdee8e5 Mon Sep 17 00:00:00 2001 From: arvinwli Date: Tue, 7 Nov 2023 16:53:33 +0800 Subject: [PATCH 13/13] feat(renderer): reset time when setPage and format code --- .../viewPager/NativeRenderViewPager.mm | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm index 1f28a40159c..670f2fc8b60 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.mm @@ -163,7 +163,8 @@ - (void)setPage:(NSInteger)pageNumber animated:(BOOL)animated { HippyLogWarn(@"Error In ViewPager setPage: pageNumber invalid"); return; } - + // reset time,Avoid the next event not send + self._lastScrollDispatchTime = -1; _lastPageIndex = pageNumber; UIView *theItem = self.viewPagerItems[pageNumber]; self.targetContentOffsetX = CGRectGetMinX(theItem.frame); @@ -205,7 +206,6 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { } else { self.mHasUnsentScrollEvent = true; } - } for (NSObject *scrollViewListener in _scrollViewListener) { @@ -250,7 +250,7 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL self.isScrolling = NO; } - if(!decelerate) { + if (!decelerate) { [self onScrollIdle]; } if (self.onPageScrollStateChanged) { @@ -514,21 +514,20 @@ - (bool)checkSendOnScrollEvent { return false; } -- (void)sendOnPageScrollEvent: (NSUInteger)position positionOffset:(CGFloat) positionOffset{ +- (void)sendOnPageScrollEvent:(NSUInteger)position positionOffset:(CGFloat)positionOffset { self.mHasUnsentScrollEvent = false; self.onPageScroll(@{ - @"position": @(position), - @"offset": @(positionOffset), + @"position" : @(position), + @"offset" : @(positionOffset), }); } - (void)onScrollIdle { - //reset on scroll idle + // reset on scroll idle self._lastScrollDispatchTime = -1; - if(self.mHasUnsentScrollEvent) { + if (self.mHasUnsentScrollEvent) { self.mHasUnsentScrollEvent = false; [self sendOnPageScrollEvent:self.onPageScrolledPosition positionOffset:self.onPageScrollPositionOffset]; } } - @end