From 63867295115e6bd2e9e4c0e55d321bca3f118703 Mon Sep 17 00:00:00 2001 From: Tommy Nguyen <4123478+tido64@users.noreply.github.com> Date: Mon, 29 Jun 2020 23:33:39 +0200 Subject: [PATCH] Alleviate excessive layout jittering when resizing window (#439) --- React/Base/RCTRootView.m | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index 172e5c573b9a3f..6913cdc92f69cb 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -37,6 +37,10 @@ #import "RCTDevMenu.h" #endif // ]TODO(OSS Candidate ISS#2710739) +#if TARGET_OS_OSX // [TODO(macOS ISS#2323203) +#define RCT_LAYOUT_THROTTLE 0.25 +#endif // ]TODO(macOS ISS#2323203) + NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification"; @interface RCTUIManager (RCTRootView) @@ -52,6 +56,11 @@ @implementation RCTRootView RCTRootContentView *_contentView; BOOL _passThroughTouches; CGSize _intrinsicContentSize; + +#if TARGET_OS_OSX // [TODO(macOS ISS#2323203) + NSDate *_lastLayout; + BOOL _throttleLayout; +#endif // ]TODO(macOS ISS#2323203) } - (instancetype)initWithBridge:(RCTBridge *)bridge @@ -79,6 +88,10 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge _loadingViewFadeDuration = 0.25; _sizeFlexibility = RCTRootViewSizeFlexibilityNone; +#if TARGET_OS_OSX // [TODO(macOS ISS#2323203) + _lastLayout = [NSDate new]; +#endif // ]TODO(macOS ISS#2323203) + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bridgeDidReload) name:RCTJavaScriptWillStartLoadingNotification @@ -173,6 +186,35 @@ - (CGSize)sizeThatFits:(CGSize)size return fitSize; } +#if TARGET_OS_OSX // [TODO(macOS ISS#2323203) +// TODO: https://github.com/microsoft/react-native-macos/issues/459 +// This is a workaround for window resizing events overloading the shadow queue: +// - https://github.com/microsoft/react-native-macos/issues/322 +// - https://github.com/microsoft/react-native-macos/issues/422 +// We should revisit this issue when we switch over to Fabric. +- (void)layout +{ + if (self.window != nil && !_throttleLayout) { + NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:_lastLayout]; + if (interval >= RCT_LAYOUT_THROTTLE) { + _lastLayout = [NSDate new]; + [self layoutSubviews]; + } else { + _throttleLayout = YES; + __weak typeof(self) weakSelf = self; + int64_t delta = (RCT_LAYOUT_THROTTLE - interval) * NSEC_PER_SEC; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta), dispatch_get_main_queue(), ^{ + typeof(self) strongSelf = weakSelf; + if (strongSelf != nil) { + strongSelf->_throttleLayout = NO; + [strongSelf setNeedsLayout]; + } + }); + } + } +} +#endif // ]TODO(macOS ISS#2323203) + - (void)layoutSubviews { [super layoutSubviews];