Skip to content

Commit 166e371

Browse files
authored
fix(paper): prevent freeze on layout update during transition (#941)
* fix(paper): prevent freeze on layout update during transition * chore: add comment
1 parent 5ac4b7e commit 166e371

File tree

5 files changed

+56
-15
lines changed

5 files changed

+56
-15
lines changed

ios/RNCPagerView.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1+
#import <React/RCTView.h>
12
#import <React/RCTEventDispatcher.h>
23
#import <React/RCTShadowView.h>
3-
#import <React/UIView+React.h>
44
#import <UIKit/UIKit.h>
55
#import "UIView+isHorizontalRtlLayout.h"
66

77
NS_ASSUME_NONNULL_BEGIN
88

9-
@interface RNCPagerView: UIView <RtlLayoutProtocol>
9+
@interface RNCPagerView: RCTView <RtlLayoutProtocol>
1010

11-
- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol> )eventDispatcher;
11+
- (instancetype)initWithBridge:(RCTBridge *)bridge;
1212

1313
@property(nonatomic) NSInteger initialPage;
1414
@property(nonatomic) NSInteger lastReportedIndex;
@@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
2525
@property(nonatomic, copy) RCTDirectEventBlock onPageScrollStateChanged;
2626
@property(nonatomic) BOOL overdrag;
2727
@property(nonatomic) NSString* layoutDirection;
28-
@property(nonatomic, assign) BOOL animating;
28+
@property(nonatomic, assign) BOOL transitioning;
2929

3030
- (void)goTo:(NSInteger)index animated:(BOOL)animated;
3131
- (void)shouldScroll:(BOOL)scrollEnabled;

ios/RNCPagerView.m

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#import "RNCPagerView.h"
22
#import <React/RCTLog.h>
33
#import <React/RCTViewManager.h>
4+
#import <React/RCTUIManager.h>
45

56
#import "UIViewController+CreateExtension.h"
67
#import "RCTOnPageScrollEvent.h"
@@ -13,7 +14,7 @@ @interface RNCPagerView () <UIPageViewControllerDataSource, UIPageViewController
1314
@property(nonatomic, assign) UIPanGestureRecognizer* panGestureRecognizer;
1415

1516
@property(nonatomic, strong) UIPageViewController *reactPageViewController;
16-
@property(nonatomic, strong) RCTEventDispatcher *eventDispatcher;
17+
@property(nonatomic, strong) id<RCTEventDispatcherProtocol> eventDispatcher;
1718

1819
@property(nonatomic, weak) UIScrollView *scrollView;
1920
@property(nonatomic, weak) UIView *currentView;
@@ -30,10 +31,12 @@ - (void)shouldDismissKeyboard:(NSString *)dismissKeyboard;
3031

3132
@implementation RNCPagerView {
3233
uint16_t _coalescingKey;
34+
__weak RCTBridge * _bridge;
3335
}
3436

35-
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher {
37+
- (instancetype)initWithBridge:(RCTBridge *)bridge {
3638
if (self = [super init]) {
39+
_bridge = bridge;
3740
_scrollEnabled = YES;
3841
_pageMargin = 0;
3942
_lastReportedIndex = -1;
@@ -44,7 +47,7 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher {
4447
_dismissKeyboard = UIScrollViewKeyboardDismissModeNone;
4548
#endif
4649
_coalescingKey = 0;
47-
_eventDispatcher = eventDispatcher;
50+
_eventDispatcher = bridge.eventDispatcher;
4851
_cachedControllers = [NSHashTable hashTableWithOptions:NSHashTableStrongMemory];
4952
_overdrag = NO;
5053
_layoutDirection = @"ltr";
@@ -178,7 +181,7 @@ - (void)setReactViewControllers:(NSInteger)index
178181
uint16_t coalescingKey = _coalescingKey++;
179182

180183
if (animated == YES) {
181-
self.animating = YES;
184+
[self setTransitioning:YES];
182185
}
183186

184187
[self.reactPageViewController setViewControllers:@[controller]
@@ -190,10 +193,8 @@ - (void)setReactViewControllers:(NSInteger)index
190193
strongSelf.currentView = controller.view;
191194

192195
[strongSelf enableSwipe];
193-
194-
if (finished) {
195-
strongSelf.animating = NO;
196-
}
196+
197+
[strongSelf setTransitioning:NO];
197198

198199
if (strongSelf.eventDispatcher) {
199200
if (strongSelf.lastReportedIndex != strongSelf.currentIndex) {
@@ -245,6 +246,11 @@ - (void)enableSwipe {
245246
self.reactPageViewController.view.userInteractionEnabled = YES;
246247
}
247248

249+
- (void)setTransitioning:(BOOL)transitioning {
250+
_transitioning = transitioning;
251+
[_bridge.uiManager setLocalData:@{@"transitioning": @(transitioning)} forView:self];
252+
}
253+
248254
- (void)goTo:(NSInteger)index animated:(BOOL)animated {
249255
NSInteger numberOfPages = self.reactSubviews.count;
250256

@@ -267,7 +273,7 @@ - (void)goTo:(NSInteger)index animated:(BOOL)animated {
267273

268274
long diff = labs(index - _currentIndex);
269275

270-
[self goToViewController:index direction:direction animated:(!self.animating && animated) shouldCallOnPageSelected: YES];
276+
[self goToViewController:index direction:direction animated:(!_transitioning && animated) shouldCallOnPageSelected: YES];
271277

272278
if (diff == 0) {
273279
[self goToViewController:index direction:direction animated:NO shouldCallOnPageSelected:YES];

ios/RNCPagerViewManager.m

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
#import "RNCPagerViewManager.h"
3+
#import "RNCPagerViewShadowView.h"
34

45
@implementation RNCPagerViewManager
56

@@ -30,7 +31,7 @@ - (void) goToPage
3031
RCTLogError(@"Cannot find RNCPagerView with tag #%@", reactTag);
3132
return;
3233
}
33-
if (!animated || !view.animating) {
34+
if (!animated || !view.transitioning) {
3435
[view goTo:index.integerValue animated:animated];
3536
}
3637
}];
@@ -80,7 +81,12 @@ - (void) changeScrollEnabled
8081

8182

8283
- (UIView *)view {
83-
return [[RNCPagerView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
84+
return [[RNCPagerView alloc] initWithBridge: self.bridge];
85+
}
86+
87+
88+
- (RCTShadowView *)shadowView {
89+
return [RNCPagerViewShadowView new];
8490
}
8591

8692
@end

ios/RNCPagerViewShadowView.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#import <React/RCTShadowView.h>
2+
3+
@interface RNCPagerViewShadowView : RCTShadowView
4+
5+
@end

ios/RNCPagerViewShadowView.m

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#import "RNCPagerViewShadowView.h"
2+
3+
@implementation RNCPagerViewShadowView {
4+
BOOL _transitioning;
5+
}
6+
7+
- (void)layoutWithMetrics:(RCTLayoutMetrics)layoutMetrics
8+
layoutContext:(RCTLayoutContext)layoutContext {
9+
// Prevent layout updates during a transition, as they cause the `setViewControllers`
10+
// method to skip calling its completion block.
11+
if (_transitioning) {
12+
return;
13+
}
14+
15+
[super layoutWithMetrics:layoutMetrics layoutContext:layoutContext];
16+
}
17+
18+
- (void)setLocalData:(NSDictionary *)localData {
19+
[super setLocalData:localData];
20+
21+
_transitioning = [localData[@"transitioning"] boolValue];
22+
}
23+
24+
@end

0 commit comments

Comments
 (0)