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..464e70e0ffa 100644 --- a/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h +++ b/renderer/native/ios/renderer/component/viewPager/NativeRenderViewPager.h @@ -37,6 +37,7 @@ 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..095c26cb448 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,16 @@ - (void)autoPageDown { } } +- (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)