Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand All @@ -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',
Expand All @@ -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' },
Expand Down
105 changes: 105 additions & 0 deletions example/src/NestedHorizontalScrollViewExample.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<SafeAreaView style={styles.container}>
<AnimatedPagerView
{...navigationPanel}
testID="pager-view"
ref={ref}
style={styles.PagerView}
initialPage={0}
pageMargin={10}
>
{useMemo(
() =>
navigationPanel.pages.map((page, index) => {
if (index === 1) {
return (
<ScrollView
horizontal
key={page.key}
contentContainerStyle={{ margin: 20 }}
>
<View
style={[styles.box, { backgroundColor: 'lightblue' }]}
>
<Text
testID={`pageNumber${index}`}
>{`Scroll View page number ${index}`}</Text>
</View>
<View style={styles.box}>
<Text
testID={`pageNumber${index}`}
>{`Scroll View page number ${index}`}</Text>
</View>
</ScrollView>
);
}

return (
<View
testID="pager-view-content"
key={page.key}
style={page.style}
collapsable={false}
>
<LikeCount />
<Text
testID={`pageNumber${index}`}
>{`page number ${index}`}</Text>
</View>
);
}),
[navigationPanel.pages]
)}
</AnimatedPagerView>
<NavigationPanel {...navigationPanel} />
</SafeAreaView>
);
}

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,
},
});
33 changes: 15 additions & 18 deletions ios/RNCPagerViewComponentView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -356,7 +354,6 @@ - (void)pageViewController:(UIPageViewController *)pageViewController
int position = (int) currentIndex;
const auto eventEmitter = [self pagerEventEmitter];
eventEmitter->onPageSelected(RNCViewPagerEventEmitter::OnPageSelected{.position = static_cast<double>(position)});
eventEmitter->onPageScroll(RNCViewPagerEventEmitter::OnPageScroll{.position = static_cast<double>(position), .offset = 0.0});
}
}

Expand Down
Loading