Skip to content

Commit 8038e88

Browse files
committed
fix(ios): emit onPageSelected for vertical orientation and initialPage
1 parent d2dee5e commit 8038e88

3 files changed

Lines changed: 42 additions & 3 deletions

File tree

ios/PagerScrollDelegate.swift

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class PagerScrollDelegate: NSObject, UIScrollViewDelegate, UICollectionViewDeleg
77
weak var originalDelegate: UICollectionViewDelegate?
88
weak var delegate: PagerViewProviderDelegate?
99
var orientation: UICollectionView.ScrollDirection = .horizontal
10+
var lastSelectedPage: Int = -1
11+
var isProgrammaticScroll: Bool = false
1012

1113
private let handledSelectors: Set<Selector> = [
1214
#selector(scrollViewDidScroll(_:)),
@@ -45,21 +47,45 @@ class PagerScrollDelegate: NSObject, UIScrollViewDelegate, UICollectionViewDeleg
4547
}
4648

4749
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
50+
emitPageSelectedIfNeeded(scrollView)
4851
delegate?.onPageScrollStateChanged(state: .idle)
4952
originalDelegate?.scrollViewDidEndDecelerating?(scrollView)
5053
}
51-
54+
5255
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
56+
emitPageSelectedIfNeeded(scrollView)
5357
delegate?.onPageScrollStateChanged(state: .idle)
5458
originalDelegate?.scrollViewDidEndScrollingAnimation?(scrollView)
5559
}
56-
60+
5761
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
5862
if !decelerate {
63+
emitPageSelectedIfNeeded(scrollView)
5964
delegate?.onPageScrollStateChanged(state: .idle)
6065
}
6166
originalDelegate?.scrollViewDidEndDragging?(scrollView, willDecelerate: decelerate)
6267
}
68+
69+
private func emitPageSelectedIfNeeded(_ scrollView: UIScrollView) {
70+
// Skip during programmatic navigation — .onChange handles that
71+
if isProgrammaticScroll {
72+
isProgrammaticScroll = false
73+
return
74+
}
75+
76+
let isHorizontal = orientation == .horizontal
77+
let pageSize = isHorizontal ? scrollView.frame.width : scrollView.frame.height
78+
let contentOffset = isHorizontal ? scrollView.contentOffset.x : scrollView.contentOffset.y
79+
80+
guard pageSize > 0 else { return }
81+
82+
let page = Int(round(contentOffset / pageSize))
83+
84+
if page != lastSelectedPage {
85+
lastSelectedPage = page
86+
delegate?.onPageSelected(position: page)
87+
}
88+
}
6389

6490
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
6591
originalDelegate?.collectionView?(collectionView, didEndDisplaying: cell, forItemAt: indexPath)

ios/PagerView.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ struct PagerView: View {
4444
}
4545
}
4646
.onChange(of: props.currentPage) { newValue in
47-
delegate?.onPageSelected(position: newValue)
47+
if scrollDelegate.lastSelectedPage != newValue {
48+
scrollDelegate.lastSelectedPage = newValue
49+
scrollDelegate.isProgrammaticScroll = true
50+
delegate?.onPageSelected(position: newValue)
51+
}
4852
}
4953
.onChange(of: props.scrollEnabled) { newValue in
5054
collectionView?.isScrollEnabled = newValue

ios/RNCPagerViewComponentView.mm

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(cons
6767

6868
if (_pagerViewProvider.currentPage == -1) {
6969
_pagerViewProvider.currentPage = newScreenProps.initialPage;
70+
// Defer initial onPageSelected until event emitter is available
71+
if (newScreenProps.initialPage > 0) {
72+
dispatch_async(dispatch_get_main_queue(), ^{
73+
[self onPageSelectedWithPosition:newScreenProps.initialPage];
74+
});
75+
}
7076
}
7177

7278
if (oldScreenProps.scrollEnabled != newScreenProps.scrollEnabled) {
@@ -103,16 +109,19 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(cons
103109

104110
- (void)onPageScrollWithData:(OnPageScrollEventData *)data {
105111
const auto eventEmitter = [self pagerEventEmitter];
112+
if (!eventEmitter) return;
106113
[self sendScrollEventsForPosition:data.position offset:data.offset];
107114
}
108115

109116
- (void)onPageSelectedWithPosition:(NSInteger)position {
110117
const auto eventEmitter = [self pagerEventEmitter];
118+
if (!eventEmitter) return;
111119
eventEmitter->onPageSelected(RNCViewPagerEventEmitter::OnPageSelected{.position = static_cast<double>(position)});
112120
}
113121

114122
- (void)onPageScrollStateChangedWithState:(enum PageScrollState)state {
115123
const auto eventEmitter = [self pagerEventEmitter];
124+
if (!eventEmitter) return;
116125

117126
RNCViewPagerEventEmitter::OnPageScrollStateChangedPageScrollState scrollState;
118127

0 commit comments

Comments
 (0)