Skip to content

Commit

Permalink
fix(paper): prevent freeze on layout update during transition
Browse files Browse the repository at this point in the history
  • Loading branch information
krozniata committed Dec 2, 2024
1 parent b7e4af4 commit 9c804fc
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 15 deletions.
8 changes: 4 additions & 4 deletions ios/RNCPagerView.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#import <React/RCTView.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTShadowView.h>
#import <React/UIView+React.h>
#import <UIKit/UIKit.h>
#import "UIView+isHorizontalRtlLayout.h"

NS_ASSUME_NONNULL_BEGIN

@interface RNCPagerView: UIView <RtlLayoutProtocol>
@interface RNCPagerView: RCTView <RtlLayoutProtocol>

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

@property(nonatomic) NSInteger initialPage;
@property(nonatomic) NSInteger lastReportedIndex;
Expand All @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
@property(nonatomic, copy) RCTDirectEventBlock onPageScrollStateChanged;
@property(nonatomic) BOOL overdrag;
@property(nonatomic) NSString* layoutDirection;
@property(nonatomic, assign) BOOL animating;
@property(nonatomic, assign) BOOL transitioning;

- (void)goTo:(NSInteger)index animated:(BOOL)animated;
- (void)shouldScroll:(BOOL)scrollEnabled;
Expand Down
24 changes: 15 additions & 9 deletions ios/RNCPagerView.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "RNCPagerView.h"
#import "React/RCTLog.h"
#import <React/RCTViewManager.h>
#import <React/RCTUIManager.h>

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

@property(nonatomic, strong) UIPageViewController *reactPageViewController;
@property(nonatomic, strong) RCTEventDispatcher *eventDispatcher;
@property(nonatomic, strong) id<RCTEventDispatcherProtocol> eventDispatcher;

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

@implementation RNCPagerView {
uint16_t _coalescingKey;
__weak RCTBridge * _bridge;
}

- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher {
- (instancetype)initWithBridge:(RCTBridge *)bridge {
if (self = [super init]) {
_bridge = bridge;
_scrollEnabled = YES;
_pageMargin = 0;
_lastReportedIndex = -1;
Expand All @@ -44,7 +47,7 @@ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher {
_dismissKeyboard = UIScrollViewKeyboardDismissModeNone;
#endif
_coalescingKey = 0;
_eventDispatcher = eventDispatcher;
_eventDispatcher = bridge.eventDispatcher;
_cachedControllers = [NSHashTable hashTableWithOptions:NSHashTableStrongMemory];
_overdrag = NO;
_layoutDirection = @"ltr";
Expand Down Expand Up @@ -178,7 +181,7 @@ - (void)setReactViewControllers:(NSInteger)index
uint16_t coalescingKey = _coalescingKey++;

if (animated == YES) {
self.animating = YES;
[self setTransitioning:YES];
}

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

[strongSelf enableSwipe];

if (finished) {
strongSelf.animating = NO;
}

[strongSelf setTransitioning:NO];

if (strongSelf.eventDispatcher) {
if (strongSelf.lastReportedIndex != strongSelf.currentIndex) {
Expand Down Expand Up @@ -245,6 +246,11 @@ - (void)enableSwipe {
self.reactPageViewController.view.userInteractionEnabled = YES;
}

- (void)setTransitioning:(BOOL)transitioning {
_transitioning = transitioning;
[_bridge.uiManager setLocalData:@{@"transitioning": @(transitioning)} forView:self];
}

- (void)goTo:(NSInteger)index animated:(BOOL)animated {
NSInteger numberOfPages = self.reactSubviews.count;

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

long diff = labs(index - _currentIndex);

[self goToViewController:index direction:direction animated:(!self.animating && animated) shouldCallOnPageSelected: YES];
[self goToViewController:index direction:direction animated:(!_transitioning && animated) shouldCallOnPageSelected: YES];

if (diff == 0) {
[self goToViewController:index direction:direction animated:NO shouldCallOnPageSelected:YES];
Expand Down
10 changes: 8 additions & 2 deletions ios/RNCPagerViewManager.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

#import "RNCPagerViewManager.h"
#import "RNCPagerViewShadowView.h"

@implementation RNCPagerViewManager

Expand Down Expand Up @@ -30,7 +31,7 @@ - (void) goToPage
RCTLogError(@"Cannot find RNCPagerView with tag #%@", reactTag);
return;
}
if (!animated || !view.animating) {
if (!animated || !view.transitioning) {
[view goTo:index.integerValue animated:animated];
}
}];
Expand Down Expand Up @@ -80,7 +81,12 @@ - (void) changeScrollEnabled


- (UIView *)view {
return [[RNCPagerView alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
return [[RNCPagerView alloc] initWithBridge: self.bridge];
}


- (RCTShadowView *)shadowView {
return [RNCPagerViewShadowView new];
}

@end
5 changes: 5 additions & 0 deletions ios/RNCPagerViewShadowView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#import <React/RCTShadowView.h>

@interface RNCPagerViewShadowView : RCTShadowView

@end
22 changes: 22 additions & 0 deletions ios/RNCPagerViewShadowView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#import "RNCPagerViewShadowView.h"

@implementation RNCPagerViewShadowView {
BOOL _transitioning;
}

- (void)layoutWithMetrics:(RCTLayoutMetrics)layoutMetrics
layoutContext:(RCTLayoutContext)layoutContext {
if (_transitioning) {
return;
}

[super layoutWithMetrics:layoutMetrics layoutContext:layoutContext];
}

- (void)setLocalData:(NSDictionary *)localData {
[super setLocalData:localData];

_transitioning = [localData[@"transitioning"] boolValue];
}

@end

0 comments on commit 9c804fc

Please sign in to comment.