Skip to content

Commit 859bdb8

Browse files
zoontekmeta-codesync[bot]
authored andcommitted
Prevent iOS Alert and Modal from rendering in the top-left corner (#57251)
Summary: On iOS, both `Alert` and `Modal` could render in the top-left corner of the screen instead of filling it. - `RCTAlertController`: when the alert window is created from a `UIWindowScene`, it was initialized without a frame and defaulted to a zero-sized frame. We now set its frame to the scene's coordinate space bounds. - `ModalHostViewUtils`: `ModalHostViewScreenSize` used `RCTScreenSize()`, whose value is cached once via `dispatch_once`. If that first read happens before the screen is ready, it caches `0` and stays `0`, so the modal renders zero-sized in the top-left corner. We now read `RCTViewportSize()` on the main queue, which reads the key window's bounds live. Fixes #45453 ## Changelog: [IOS] [FIXED] - Prevent Alert and Modal from rendering in the top-left corner Pull Request resolved: #57251 Test Plan: - Open an `Alert` on iOS and confirm it is centered and correctly sized. - Open a `Modal` on iOS and confirm it fills the screen instead of appearing in the top-left corner. ## Screenshots: <img width="284" height="542" alt="Alert" src="https://github.com/user-attachments/assets/e98ae159-9752-4b6e-8a97-0276984af3ba" /> <img width="284" height="542" alt="Modal" src="https://github.com/user-attachments/assets/1fff4217-5f28-4017-8699-01b757e7fb8a" /> Reviewed By: javache Differential Revision: D109310703 Pulled By: cortinico fbshipit-source-id: db3d66a704921c524faed62d82695528d75698eb
1 parent b29dc96 commit 859bdb8

2 files changed

Lines changed: 12 additions & 8 deletions

File tree

packages/react-native/React/Base/RCTUtils.mm

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#import <objc/message.h>
1313
#import <objc/runtime.h>
1414
#import <zlib.h>
15+
#import <atomic>
1516

1617
#import <UIKit/UIKit.h>
1718

@@ -383,24 +384,26 @@ UIDeviceOrientation RCTDeviceOrientation(void)
383384

384385
CGSize RCTScreenSize(void)
385386
{
386-
static CGSize portraitSize;
387-
static dispatch_once_t onceToken;
388-
dispatch_once(&onceToken, ^{
387+
static std::atomic<CGSize> cachedSize;
388+
__block CGSize size = cachedSize.load(std::memory_order_relaxed);
389+
390+
if (CGSizeEqualToSize(size, CGSizeZero)) {
389391
RCTUnsafeExecuteOnMainQueueSync(^{
390392
CGSize screenSize = [UIScreen mainScreen].bounds.size;
391-
portraitSize = CGSizeMake(MIN(screenSize.width, screenSize.height), MAX(screenSize.width, screenSize.height));
393+
size = CGSizeMake(MIN(screenSize.width, screenSize.height), MAX(screenSize.width, screenSize.height));
394+
cachedSize.store(size, std::memory_order_relaxed);
392395
});
393-
});
396+
}
394397

395398
#if !TARGET_OS_TV
396399
if (UIDeviceOrientationIsLandscape(RCTDeviceOrientation())) {
397-
return CGSizeMake(portraitSize.height, portraitSize.width);
400+
return CGSizeMake(size.height, size.width);
398401
} else {
399-
return CGSizeMake(portraitSize.width, portraitSize.height);
402+
return CGSizeMake(size.width, size.height);
400403
}
401404
#else
402405
// tvOS doesn't have device orientation, always return landscape size
403-
return CGSizeMake(portraitSize.height, portraitSize.width);
406+
return CGSizeMake(size.height, size.width);
404407
#endif
405408
}
406409

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ - (UIWindow *)alertWindow
2323
UIWindowScene *scene = RCTKeyWindow().windowScene;
2424
if (scene != nil) {
2525
_alertWindow = [[UIWindow alloc] initWithWindowScene:scene];
26+
_alertWindow.frame = scene.coordinateSpace.bounds;
2627
} else {
2728
_alertWindow = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
2829
}

0 commit comments

Comments
 (0)