diff --git a/example/src/App.tsx b/example/src/App.tsx
index eb33e443..a7bb584e 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -36,6 +36,7 @@ import { MaterialTopBarExample } from './MaterialTopTabExample';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { PagerHookExample } from './PagerHookExample';
+import { NestedHorizontalScrollViewExample } from './NestedHorizontalScrollViewExample';
const examples = [
{ component: BasicPagerViewExample, name: 'Basic Example' },
@@ -50,7 +51,10 @@ const examples = [
component: ScrollablePagerViewExample,
name: 'Scrollable PagerView Example',
},
- { component: TabViewInsideScrollViewExample, name: 'TabView inside ScrollView Example' },
+ {
+ component: TabViewInsideScrollViewExample,
+ name: 'TabView inside ScrollView Example',
+ },
{
component: ScrollViewInsideExample,
name: 'ScrollView inside PagerView Example',
@@ -60,6 +64,10 @@ const examples = [
name: 'Nest PagerView Example',
},
{ component: ScrollableTabBarExample, name: 'ScrollableTabBarExample' },
+ {
+ component: NestedHorizontalScrollViewExample,
+ name: 'NestedHorizontalScrollViewExample',
+ },
{ component: AutoWidthTabBarExample, name: 'AutoWidthTabBarExample' },
{ component: TabBarIconExample, name: 'TabBarIconExample' },
{ component: CustomIndicatorExample, name: 'CustomIndicatorExample' },
diff --git a/example/src/NestedHorizontalScrollViewExample.tsx b/example/src/NestedHorizontalScrollViewExample.tsx
new file mode 100644
index 00000000..daf1c8fb
--- /dev/null
+++ b/example/src/NestedHorizontalScrollViewExample.tsx
@@ -0,0 +1,105 @@
+import React, { useMemo } from 'react';
+import {
+ StyleSheet,
+ View,
+ SafeAreaView,
+ Animated,
+ Text,
+ ScrollView,
+} from 'react-native';
+
+import PagerView from 'react-native-pager-view';
+
+import { LikeCount } from './component/LikeCount';
+import { NavigationPanel } from './component/NavigationPanel';
+import { useNavigationPanel } from './hook/useNavigationPanel';
+
+const AnimatedPagerView = Animated.createAnimatedComponent(PagerView);
+
+/**
+ * When dragging the horizontal ScrollView inside the PagerView, it can slightly push pager view into a different page.
+ * This is because scrollview in the same direction overdrags the outer scrollview (pager view).
+ * This example reproduces this behavior.
+ * Go to the second page and try to drag the horizontal scrollview.
+ */
+export function NestedHorizontalScrollViewExample() {
+ const { ref, ...navigationPanel } = useNavigationPanel(3);
+
+ return (
+
+
+ {useMemo(
+ () =>
+ navigationPanel.pages.map((page, index) => {
+ if (index === 1) {
+ return (
+
+
+ {`Scroll View page number ${index}`}
+
+
+ {`Scroll View page number ${index}`}
+
+
+ );
+ }
+
+ return (
+
+
+ {`page number ${index}`}
+
+ );
+ }),
+ [navigationPanel.pages]
+ )}
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: 'white',
+ },
+ image: {
+ width: 300,
+ height: 200,
+ padding: 20,
+ },
+ PagerView: {
+ flex: 1,
+ },
+ box: {
+ width: 300,
+ height: '100%',
+ backgroundColor: 'lightgreen',
+ padding: 20,
+ },
+});
diff --git a/ios/RNCPagerViewComponentView.mm b/ios/RNCPagerViewComponentView.mm
index c6a150b0..ccc2595b 100644
--- a/ios/RNCPagerViewComponentView.mm
+++ b/ios/RNCPagerViewComponentView.mm
@@ -296,53 +296,51 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
- CGFloat contentOffset = [self isHorizontal] ? scrollView.contentOffset.x : scrollView.contentOffset.y;
- CGFloat frameSize = [self isHorizontal] ? scrollView.frame.size.width : scrollView.frame.size.height;
-
+ BOOL isHorizontal = [self isHorizontal];
+ CGFloat contentOffset = isHorizontal ? scrollView.contentOffset.x : scrollView.contentOffset.y;
+ CGFloat frameSize = isHorizontal ? scrollView.frame.size.width : scrollView.frame.size.height;
+
if (frameSize == 0) {
return;
}
- float offset = (contentOffset - frameSize)/frameSize;
-
+ float offset = (contentOffset - frameSize) / frameSize;
float absoluteOffset = fabs(offset);
-
NSInteger position = _currentIndex;
BOOL isHorizontalRtl = [self isHorizontalRtlLayout];
BOOL isAnimatingBackwards = isHorizontalRtl ? offset > 0.05f : offset < 0;
-
- if (scrollView.isDragging) {
+ BOOL isBeingMovedByNestedScrollView = !scrollView.isDragging && !scrollView.isTracking;
+ if (scrollView.isDragging || isBeingMovedByNestedScrollView) {
_destinationIndex = isAnimatingBackwards ? _currentIndex - 1 : _currentIndex + 1;
}
if (isAnimatingBackwards) {
- position = _destinationIndex;
- absoluteOffset = fmax(0, 1 - absoluteOffset);
+ position = _destinationIndex;
+ absoluteOffset = fmax(0, 1 - absoluteOffset);
}
if (!_overdrag) {
NSInteger maxIndex = _nativeChildrenViewControllers.count - 1;
- NSInteger firstPageIndex = !isHorizontalRtl ? 0 : maxIndex;
- NSInteger lastPageIndex = !isHorizontalRtl ? maxIndex : 0;
+ NSInteger firstPageIndex = isHorizontalRtl ? maxIndex : 0;
+ NSInteger lastPageIndex = isHorizontalRtl ? 0 : maxIndex;
BOOL isFirstPage = _currentIndex == firstPageIndex;
BOOL isLastPage = _currentIndex == lastPageIndex;
- CGFloat contentOffset =[self isHorizontal] ? scrollView.contentOffset.x : scrollView.contentOffset.y;
- CGFloat topBound = [self isHorizontal] ? scrollView.bounds.size.width : scrollView.bounds.size.height;
+ CGFloat topBound = isHorizontal ? scrollView.bounds.size.width : scrollView.bounds.size.height;
if ((isFirstPage && contentOffset <= topBound) || (isLastPage && contentOffset >= topBound)) {
- CGPoint croppedOffset = [self isHorizontal] ? CGPointMake(topBound, 0) : CGPointMake(0, topBound);
+ CGPoint croppedOffset = isHorizontal ? CGPointMake(topBound, 0) : CGPointMake(0, topBound);
scrollView.contentOffset = croppedOffset;
- absoluteOffset=0;
+ absoluteOffset = 0;
position = isLastPage ? lastPageIndex : firstPageIndex;
}
}
float interpolatedOffset = absoluteOffset * labs(_destinationIndex - _currentIndex);
-
[self sendScrollEventsForPosition:position offset:interpolatedOffset];
}
+
#pragma mark - UIPageViewControllerDelegate
- (void)pageViewController:(UIPageViewController *)pageViewController
@@ -356,7 +354,6 @@ - (void)pageViewController:(UIPageViewController *)pageViewController
int position = (int) currentIndex;
const auto eventEmitter = [self pagerEventEmitter];
eventEmitter->onPageSelected(RNCViewPagerEventEmitter::OnPageSelected{.position = static_cast(position)});
- eventEmitter->onPageScroll(RNCViewPagerEventEmitter::OnPageScroll{.position = static_cast(position), .offset = 0.0});
}
}