@onekeyfe/react-native-pager-view 3.0.166 → 3.0.168

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -695,13 +695,13 @@ private class NativeScrollerRefreshLayout(context: Context) : SwipeRefreshLayout
695
695
  ancestor = ancestor.parent as? View
696
696
  }
697
697
  intercepted = false
698
- } else if (event.actionMasked == MotionEvent.ACTION_MOVE && (!smoothPagerGesture || !vertical)) {
698
+ } else if (event.actionMasked == MotionEvent.ACTION_MOVE && (!smoothPagerGesture || (!vertical && !horizontal))) {
699
699
  val dx = abs(event.x - downX)
700
700
  val dy = abs(event.y - downY)
701
701
  if (smoothPagerGesture && dy > slop && dy > dx) {
702
702
  vertical = true
703
703
  horizontal = false
704
- } else if (dx > (if (smoothPagerGesture) 32f * resources.displayMetrics.density else slop.toFloat()) && dx > dy) {
704
+ } else if ((if (smoothPagerGesture) dx >= 32f * resources.displayMetrics.density else dx > slop) && dx > dy) {
705
705
  horizontal = true
706
706
  }
707
707
  }
package/docs/SPEC.md CHANGED
@@ -244,9 +244,19 @@ of the refresh boundary. Dispatch MUST still observe child-owned movement; only
244
244
  a confirmed vertical Smooth Home gesture may release the viewport's child
245
245
  interception prohibition. Pending and horizontal movement MUST preserve it.
246
246
 
247
+ In smooth-header mode, Android's NativeScroller refresh boundary MUST retain a
248
+ confirmed horizontal or vertical direction until the touch sequence ends or is
249
+ cancelled. It MUST classify MOVE direction only while neither direction is confirmed,
250
+ and horizontal confirmation MUST include the 32 dp boundary, matching the
251
+ viewport. Later vertical movement after confirmed horizontal intent MUST NOT
252
+ start a refresh gesture. Non-smooth refresh direction behavior remains unchanged.
253
+
247
254
  iOS nested horizontal ownership MUST include enabled nonpaging horizontal-only
248
255
  ScrollViews, with content wider than bounds and no vertical content overflow.
249
256
  Both pan holding and failure dependencies MUST use the same eligibility. A
257
+ failure dependency on the Pager guard MUST apply only to the horizontal pan;
258
+ independent non-pan recognizers, including stationary native long presses, MUST
259
+ remain able to recognize before finger-up while Pager intent is pending. A
250
260
  second touch in the pending Pager guard fails recognition; an already active
251
261
  Pager guard cancels and restores each held pan's original minimum touch count.
252
262
 
@@ -199,9 +199,7 @@ static void RNCGuardNestedHorizontalPans(UIView *view, UIGestureRecognizer *guar
199
199
  if ([view isKindOfClass:UIScrollView.class]) {
200
200
  UIScrollView *scroll = (UIScrollView *)view;
201
201
  if (RNCIsEnabledHorizontalScrollOwner(scroll)) {
202
- for (UIGestureRecognizer *gesture in scroll.gestureRecognizers) {
203
- [gesture requireGestureRecognizerToFail:guard];
204
- }
202
+ [scroll.panGestureRecognizer requireGestureRecognizerToFail:guard];
205
203
  }
206
204
  }
207
205
  for (UIView *child in view.subviews) RNCGuardNestedHorizontalPans(child, guard);
@@ -165,7 +165,9 @@ typedef struct __IOHIDEvent *RNCTestHIDEventRef;
165
165
  [_window sendEvent:_event];
166
166
  if (phase == UITouchPhaseEnded || phase == UITouchPhaseCancelled) {
167
167
  [_activeTouches removeObjectIdenticalTo:changed];
168
- if (_activeTouches.count == 0) [_event _clearTouches];
168
+ // A finished finger must not be delivered again when another finger ends.
169
+ [_event _clearTouches];
170
+ for (UITouch *touch in _activeTouches) [_event _addTouch:touch forDelayedDelivery:NO];
169
171
  }
170
172
  }
171
173
 
@@ -621,6 +623,7 @@ typedef struct __IOHIDEvent *RNCTestHIDEventRef;
621
623
  @property (nonatomic, strong) RNCCollapsiblePagerViewComponentView *pager;
622
624
  @property (nonatomic, strong) RNCSynthesizedTouchDriver *driver;
623
625
  @property (nonatomic, strong) UIView *firstPage;
626
+ @property (nonatomic) NSUInteger longPressBegins;
624
627
  @end
625
628
 
626
629
  @implementation RNCCollapsiblePagerPressCancellationDeliveryTests
@@ -809,4 +812,111 @@ typedef struct __IOHIDEvent *RNCTestHIDEventRef;
809
812
  XCTAssertEqualObjects(self.handler.events, (@[@"began", @"moved", @"ended"]));
810
813
  }
811
814
 
815
+ - (UIScrollView *)mountNestedHorizontalScrollView
816
+ {
817
+ UIScrollView *vertical = [[UIScrollView alloc] initWithFrame:self.firstPage.bounds];
818
+ vertical.contentSize = CGSizeMake(CGRectGetWidth(vertical.bounds), 1800);
819
+ [self.firstPage addSubview:vertical];
820
+ UIScrollView *horizontal = [[UIScrollView alloc] initWithFrame:CGRectMake(40, 350, 300, 120)];
821
+ horizontal.contentSize = CGSizeMake(900, 120);
822
+ horizontal.contentOffset = CGPointMake(200, 0);
823
+ [vertical addSubview:horizontal];
824
+ UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
825
+ initWithTarget:self action:@selector(nestedLongPress:)];
826
+ longPress.minimumPressDuration = 0.1;
827
+ [horizontal addGestureRecognizer:longPress];
828
+ // Re-run the production attachment path after the descendant mounts.
829
+ ((void (*)(id, SEL))objc_msgSend)(self.pager, NSSelectorFromString(@"attachScrollObserverForCurrentPage"));
830
+ [self.window layoutIfNeeded];
831
+ [self drainMainQueue];
832
+ XCTAssertEqual([self.pager valueForKey:@"observedScrollView"], vertical);
833
+ return horizontal;
834
+ }
835
+
836
+ - (void)nestedLongPress:(UILongPressGestureRecognizer *)recognizer
837
+ {
838
+ if (recognizer.state == UIGestureRecognizerStateBegan) self.longPressBegins += 1;
839
+ }
840
+
841
+ - (CGPoint)pressPointInNestedScrollView:(UIScrollView *)scroll
842
+ {
843
+ CGPoint point = [scroll convertPoint:CGPointMake(scroll.contentOffset.x + 150, 60) toView:self.window];
844
+ XCTAssertEqual([self.window hitTest:point withEvent:nil], scroll);
845
+ return point;
846
+ }
847
+
848
+ - (void)testNestedStationaryNativeLongPressRecognizesBeforeFingerUp
849
+ {
850
+ UIScrollView *scroll = [self mountNestedHorizontalScrollView];
851
+ UITouch *touch = [self.driver beginAt:[self pressPointInNestedScrollView:scroll]];
852
+ UIGestureRecognizer *guard = [self.pager valueForKey:@"verticalPagerGesture"];
853
+ XCTAssertEqual(guard.state, UIGestureRecognizerStatePossible);
854
+ XCTAssertEqual(scroll.panGestureRecognizer.minimumNumberOfTouches, 2);
855
+ XCTestExpectation *hold = [self expectationWithDescription:@"stationary finger held"];
856
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)),
857
+ dispatch_get_main_queue(), ^{ [hold fulfill]; });
858
+ [self waitForExpectations:@[hold] timeout:2];
859
+ // The real UIKit target action must arrive while the finger is still down.
860
+ XCTAssertEqual(self.longPressBegins, 1);
861
+ XCTAssertEqual(touch.phase, UITouchPhaseBegan);
862
+ XCTAssertEqual(guard.state, UIGestureRecognizerStatePossible);
863
+ [self.driver end:touch];
864
+ XCTAssertEqual(scroll.panGestureRecognizer.minimumNumberOfTouches, 1);
865
+ }
866
+
867
+ - (void)testNestedHorizontalPanConsumesConfirmedHorizontalDrag
868
+ {
869
+ UIScrollView *scroll = [self mountNestedHorizontalScrollView];
870
+ CGPoint point = [self pressPointInNestedScrollView:scroll];
871
+ CGFloat originalOffset = scroll.contentOffset.x;
872
+ UITouch *touch = [self.driver beginAt:point];
873
+ for (NSInteger step = 1; step <= 10; ++step) {
874
+ [self.driver move:touch to:CGPointMake(point.x - 12 * step, point.y)];
875
+ }
876
+ XCTAssertTrue(scroll.isDragging);
877
+ XCTAssertGreaterThan(scroll.contentOffset.x, originalOffset);
878
+ UIScrollView *pager = [self.pager valueForKey:@"pagerScrollView"];
879
+ XCTAssertFalse(pager.isDragging);
880
+ XCTAssertEqual(self.longPressBegins, 0);
881
+ [self.driver end:touch];
882
+ XCTAssertEqual(scroll.panGestureRecognizer.minimumNumberOfTouches, 1);
883
+ }
884
+
885
+ - (void)testNestedPendingHorizontalStartCanBecomeVertical
886
+ {
887
+ UIScrollView *scroll = [self mountNestedHorizontalScrollView];
888
+ CGPoint point = [self pressPointInNestedScrollView:scroll];
889
+ UITouch *touch = [self.driver beginAt:point];
890
+ [self.driver move:touch to:CGPointMake(point.x - 8, point.y)];
891
+ UIGestureRecognizer *guard = [self.pager valueForKey:@"verticalPagerGesture"];
892
+ XCTAssertEqual(guard.state, UIGestureRecognizerStatePossible);
893
+ for (NSInteger step = 1; step <= 8; ++step) {
894
+ [self.driver move:touch to:CGPointMake(point.x - 8, point.y - 12 * step)];
895
+ }
896
+ UIScrollView *vertical = [self.pager valueForKey:@"observedScrollView"];
897
+ UIScrollView *pager = [self.pager valueForKey:@"pagerScrollView"];
898
+ XCTAssertTrue(vertical.isDragging);
899
+ XCTAssertFalse(scroll.isDragging);
900
+ XCTAssertFalse(pager.isDragging);
901
+ XCTAssertEqual(self.longPressBegins, 0);
902
+ [self.driver end:touch];
903
+ XCTAssertEqual(scroll.panGestureRecognizer.minimumNumberOfTouches, 1);
904
+ XCTAssertEqual(pager.panGestureRecognizer.minimumNumberOfTouches, 1);
905
+ }
906
+
907
+ - (void)testNestedHeldPanTouchCountRestoresOnSecondTouch
908
+ {
909
+ UIScrollView *scroll = [self mountNestedHorizontalScrollView];
910
+ CGPoint point = [self pressPointInNestedScrollView:scroll];
911
+ UITouch *first = [self.driver beginAt:point];
912
+ XCTAssertEqual(scroll.panGestureRecognizer.minimumNumberOfTouches, 2);
913
+ UITouch *second = [self.driver beginAt:CGPointMake(point.x + 20, point.y)];
914
+ UIScrollView *pager = [self.pager valueForKey:@"pagerScrollView"];
915
+ XCTAssertEqual(scroll.panGestureRecognizer.minimumNumberOfTouches, 1);
916
+ XCTAssertEqual(pager.panGestureRecognizer.minimumNumberOfTouches, 1);
917
+ [self.driver end:second];
918
+ [self.driver end:first];
919
+ XCTAssertEqual(scroll.panGestureRecognizer.minimumNumberOfTouches, 1);
920
+ }
921
+
812
922
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-pager-view",
3
- "version": "3.0.166",
3
+ "version": "3.0.168",
4
4
  "description": "React Native wrapper for Android and iOS ViewPager",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/module/index.js",
@@ -72,7 +72,7 @@
72
72
  "typescript": "^5.9.2"
73
73
  },
74
74
  "peerDependencies": {
75
- "@onekeyfe/react-native-native-logger": "3.0.166",
75
+ "@onekeyfe/react-native-native-logger": "3.0.168",
76
76
  "react": "*",
77
77
  "react-native": "*"
78
78
  },