Skip to content

Commit 1c8df99

Browse files
jpdriverSaadnajmi
authored andcommitted
iOS: trigger didUpdateDimensions event when resizing without changing traits (facebook#37649)
Summary: - when using the `useWindowDimensions()` hook in a component, it's possible for the hook to report incorrect sizes and not update as frequently as it should - this is most applicable to apps built for iPad and macOS - closes facebook#36118 - either when resizing a React Native app to a different [Size Class](https://developer.apple.com/design/human-interface-guidelines/layout#Device-size-classes) or changing the Appearance, we dispatch an `RCTUserInterfaceStyleDidChangeNotification` notification - these are then handled in the `interfaceFrameDidChange` method of `RCTDeviceInfo` - this results in a `didUpdateDimensions` Device Event, which in turn updates the results of `useWindowDimensions()` - see [RCTDeviceInfo.mm#L217-L232](https://github.com/facebook/react-native/blob/v0.72.0-rc.4/packages/react-native/React/CoreModules/RCTDeviceInfo.mm#L217-L232) - and [Dimensions.js#L119-L124](https://github.com/facebook/react-native/blob/v0.72.0-rc.4/packages/react-native/Libraries/Utilities/Dimensions.js#L119-L124) 🐛 **However** 🐛 - if you are resizing without triggering a `UITraitCollection` change, the Dimensions reported by `useWindowDimensions()` can become stale, until you either:- - hit a certain width that is considered a different Size Class - change the Appearance - background then resume the app - make the app full-screen - added a new `RCTRootViewFrameDidChangeNotification` notification - the thinking here is to avoid additional overhead by re-using the same `RCTUserInterfaceStyleDidChangeNotification` - maybe it's overkill? - the new notifications are sent from an override of `setFrame` on `RCTRootView` - the new notifications call the same `interfaceFrameDidChange` method of `RCTDeviceInfo` - Dimensions are now reported correctly when resizing; even within the same Size Class <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [IOS] [FIXED] - Dimensions could be reported incorrectly when resizing iPad or macOS apps Pull Request resolved: facebook#37649 Test Plan: **Reproduction: https://github.com/jpdriver/Dimensions** or to recreate it yourself:- - Generate a new project - Change App.tsx ``` import * as React from 'react'; import {View, Text, useWindowDimensions} from 'react-native'; export default function App() { const {width, height} = useWindowDimensions(); return ( <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}> <Text>Width: {width}</Text> <Text>Height: {height}</Text> </View> ); } ``` - Open the iOS project in Xcode and enable iPad support - Enable the iPad app to be used in any orientation - Run the app - Enable Stage Manager - Drag one of the corners to resize the app Reviewed By: javache Differential Revision: D46335537 Pulled By: NickGerleman fbshipit-source-id: 1533f511cf3805fdc9629a2ee115cc00e204d82c
1 parent 0e0d2b8 commit 1c8df99

File tree

5 files changed

+21
-1
lines changed

5 files changed

+21
-1
lines changed

packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@
5050
* - (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
5151
*/
5252
#if !TARGET_OS_OSX // [macOS]
53-
@interface RCTAppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
53+
@interface RCTAppDelegate : UIResponder <UIApplicationDelegate, UISceneDelegate, RCTBridgeDelegate>
5454
#else // [macOS
5555
@interface RCTAppDelegate : NSResponder <NSApplicationDelegate, RCTBridgeDelegate>
5656
#endif // macOS]
57+
5758
/// The window object, used to render the UViewControllers
5859
@property (nonatomic, strong) RCTPlatformWindow *window; // [macOS]
5960
@property (nonatomic, strong) RCTBridge *bridge;

packages/react-native/Libraries/AppDelegate/RCTAppDelegate.mm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification
8989
UIViewController *rootViewController = [self createRootViewController];
9090
rootViewController.view = rootView;
9191
self.window.rootViewController = rootViewController;
92+
self.window.windowScene.delegate = self;
9293
[self.window makeKeyAndVisible];
9394

9495
return YES;
@@ -173,6 +174,15 @@ - (BOOL)runtimeSchedulerEnabled
173174
return YES;
174175
}
175176

177+
#pragma mark - UISceneDelegate
178+
- (void)windowScene:(UIWindowScene *)windowScene
179+
didUpdateCoordinateSpace:(id<UICoordinateSpace>)previousCoordinateSpace
180+
interfaceOrientation:(UIInterfaceOrientation)previousInterfaceOrientation
181+
traitCollection:(UITraitCollection *)previousTraitCollection API_AVAILABLE(ios(13.0))
182+
{
183+
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRootViewFrameDidChangeNotification object:self];
184+
}
185+
176186
#pragma mark - RCTCxxBridgeDelegate
177187
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
178188
{

packages/react-native/React/Base/RCTConstants.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
RCT_EXTERN NSString *const RCTUserInterfaceStyleDidChangeNotification;
1111
RCT_EXTERN NSString *const RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey;
1212

13+
RCT_EXTERN NSString *const RCTRootViewFrameDidChangeNotification;
14+
1315
/**
1416
* This notification fires when the bridge initializes.
1517
*/

packages/react-native/React/Base/RCTConstants.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
1111
NSString *const RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey = @"traitCollection";
1212

13+
NSString *const RCTRootViewFrameDidChangeNotification = @"RCTRootViewFrameDidChangeNotification";
14+
1315
NSString *const RCTJavaScriptDidFailToLoadNotification = @"RCTJavaScriptDidFailToLoadNotification";
1416
NSString *const RCTJavaScriptDidLoadNotification = @"RCTJavaScriptDidLoadNotification";
1517
NSString *const RCTJavaScriptWillStartExecutingNotification = @"RCTJavaScriptWillStartExecutingNotification";

packages/react-native/React/CoreModules/RCTDeviceInfo.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ - (void)initialize
7373
selector:@selector(interfaceFrameDidChange)
7474
name:RCTUserInterfaceStyleDidChangeNotification
7575
object:nil];
76+
77+
[[NSNotificationCenter defaultCenter] addObserver:self
78+
selector:@selector(interfaceFrameDidChange)
79+
name:RCTRootViewFrameDidChangeNotification
80+
object:nil];
7681
#endif // [macOS]
7782
}
7883

0 commit comments

Comments
 (0)