Skip to content

Commit 961af95

Browse files
authored
iOS: Update layout on device rotation (#32)
* iOS: Support rotation on new arch * iOS: Support rotation on old arch * revert package.json changes * Refactor class initializers
1 parent f1f43f6 commit 961af95

File tree

6 files changed

+69
-23
lines changed

6 files changed

+69
-23
lines changed

ios/Fabric/RNTModalViewComponentView.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ NS_ASSUME_NONNULL_BEGIN
1919

2020
@end
2121

22+
@interface RNTModalViewComponentView () <RNTModalViewControllerDelegate>
23+
24+
@end
25+
2226
NS_ASSUME_NONNULL_END
2327

2428
#endif /* RNTModalViewComponentView_h */

ios/Fabric/RNTModalViewComponentView.mm

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#import <react/renderer/components/multiplemodals/RCTComponentViewHelpers.h>
88
#import <react/renderer/components/multiplemodals/RNTModalViewComponentDescriptor.h>
99
#import <react/renderer/components/multiplemodals/RNTModalViewShadowNode.h>
10+
#import <react/renderer/components/multiplemodals/RNTModalViewState.h>
1011

1112
#import <React/RCTConversions.h>
1213
#import <React/RCTFabricComponentsPlugins.h>
@@ -42,7 +43,7 @@ - (instancetype)initWithFrame:(CGRect)frame
4243
_props = defaultProps;
4344

4445
_touchHandler = [RCTSurfaceTouchHandler new];
45-
_modalViewController = [[RNTModalViewController alloc] init];
46+
_modalViewController = [[RNTModalViewController alloc] initWithDelegate:self];
4647
_mountingHelper = [[RNTModalMountingHelper alloc] initWithViewController:_modalViewController];
4748
}
4849

@@ -83,6 +84,16 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
8384
[super updateProps:props oldProps:oldProps];
8485
}
8586

87+
#pragma mark - RNTModalViewControllerDelegate
88+
89+
- (void)boundsDidChange:(CGRect)newBounds
90+
{
91+
if (_state != nullptr) {
92+
auto newState = RNTModalViewState{RCTSizeFromCGSize(newBounds.size)};
93+
_state->updateState(std::move(newState));
94+
}
95+
}
96+
8697
#pragma mark - RCTComponentViewProtocol
8798

8899
+ (ComponentDescriptorProvider)componentDescriptorProvider

ios/Library/RNTModalViewController/RNTModalViewController.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#import <UIKit/UIKit.h>
55
#import "ModalAnimation.h"
66

7+
@protocol RNTModalViewControllerDelegate <NSObject>
8+
- (void)boundsDidChange:(CGRect)newBounds;
9+
@end
10+
711
@protocol RNTModalViewControllerProtocol <NSObject>
812
- (void)presentOn:(UIViewController *)parentVC onView:(UIView *)parentView;
913
- (void)dismiss;
@@ -13,9 +17,19 @@
1317
@end
1418

1519
@interface RNTModalViewController : UIViewController <RNTModalViewControllerProtocol>
20+
- (instancetype)init NS_UNAVAILABLE;
21+
- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;
22+
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil NS_UNAVAILABLE;
23+
24+
- (instancetype)initWithDelegate:(id<RNTModalViewControllerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
25+
26+
@property(nonatomic, weak) id<RNTModalViewControllerDelegate> delegate;
1627
@property(nonatomic, strong) UIView *reactSubviewContainer;
1728
@property(nonatomic, strong) ModalAnimation *inAnimation;
1829
@property(nonatomic, strong) ModalAnimation *outAnimation;
30+
@property(nonatomic, assign) CGRect lastBounds;
31+
@property(nonatomic, assign) BOOL shouldTrackRotationChange;
32+
1933
@end
2034

2135
#endif /* RNTModalViewController_h */

ios/Library/RNTModalViewController/RNTModalViewController.m

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,16 @@
99

1010
@implementation RNTModalViewController
1111

12-
- (instancetype)init {
12+
- (instancetype)initWithDelegate:(id<RNTModalViewControllerDelegate>)delegate {
1313
self = [super initWithNibName:nil bundle:nil];
1414
if (self) {
15-
_reactSubviewContainer = [[UIView alloc] init];
15+
self.reactSubviewContainer = [[UIView alloc] init];
16+
self.delegate = delegate;
17+
self.shouldTrackRotationChange = NO;
1618
}
1719
return self;
1820
}
1921

20-
- (instancetype)initWithCoder:(NSCoder *)coder {
21-
[NSException raise:@"initWithCoder" format:@"init(coder:) has not been implemented"];
22-
self = [super initWithNibName:nil bundle:nil];
23-
return self;
24-
}
25-
2622
- (void)setupReactSubview:(UIView *)subview {
2723
[self.view addSubview:self.reactSubviewContainer];
2824
self.reactSubviewContainer.translatesAutoresizingMaskIntoConstraints = NO;
@@ -43,7 +39,18 @@ - (void)viewDidLoad {
4339
}
4440

4541
- (void)viewDidAppear:(BOOL)animated {
46-
[self.inAnimation animate:self.reactSubviewContainer completion:NULL];
42+
[self.inAnimation animate:self.reactSubviewContainer completion:^(BOOL finished) {
43+
self.shouldTrackRotationChange = YES;
44+
}];
45+
}
46+
47+
- (void)viewDidLayoutSubviews
48+
{
49+
[super viewDidLayoutSubviews];
50+
if (!CGRectEqualToRect(self.lastBounds, self.view.bounds) && self.shouldTrackRotationChange) {
51+
[self.delegate boundsDidChange:self.view.bounds];
52+
self.lastBounds = self.view.bounds;
53+
}
4754
}
4855

4956
#pragma mark - ModalViewControllerProtocol
@@ -62,7 +69,8 @@ - (void)dismiss {
6269
UIView *prevReactSubviewContainer = self.reactSubviewContainer;
6370
self.reactSubviewContainer = [self.reactSubviewContainer snapshotViewAfterScreenUpdates:NO];
6471
[prevReactSubviewContainer removeFromSuperview];
65-
72+
73+
self.shouldTrackRotationChange = NO;
6674
[self setupReactSubview:self.reactSubviewContainer];
6775
[self.outAnimation prepareAnimation:self.reactSubviewContainer];
6876
[self.outAnimation animate:self.reactSubviewContainer completion:^(BOOL finished) {

ios/RNTModalVIew.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,18 @@
1212

1313
- (instancetype)initWithBridge:(RCTBridge *)bridge;
1414

15+
@property(nonatomic, weak) RCTBridge *bridge;
16+
@property(nonatomic, weak) UIView *reactSubview;
1517
@property(nonatomic, strong) RCTTouchHandler *touchHandler;
1618
@property(nonatomic, strong) RNTModalViewController *modalViewController;
1719
@property(nonatomic, strong) RNTModalMountingHelper *mountingHelper;
1820

1921
// Props
20-
@property(nonatomic, strong) NSString *animationType;
22+
@property(nonatomic, copy) NSString *animationType;
23+
24+
@end
25+
26+
@interface RNTModalView () <RNTModalViewControllerDelegate>
2127

2228
@end
2329

ios/RNTModalView.m

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ @implementation RNTModalView
1010

1111
- (instancetype)initWithBridge:(RCTBridge *)bridge {
1212
self = [super initWithFrame:CGRectZero];
13+
1314
if (self) {
14-
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge];
15-
_modalViewController = [[RNTModalViewController alloc] init];
16-
_mountingHelper = [[RNTModalMountingHelper alloc] initWithViewController:_modalViewController];
15+
self.bridge = bridge;
16+
self.touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge];
17+
self.modalViewController = [[RNTModalViewController alloc] initWithDelegate:self];
18+
self.mountingHelper = [[RNTModalMountingHelper alloc] initWithViewController:self.modalViewController];
1719
}
1820
return self;
1921
}
@@ -25,25 +27,27 @@ - (void)layoutSubviews {
2527
[self.mountingHelper mountIfNeeded];
2628
}
2729

28-
- (void)addSubview:(UIView *)view {
29-
[super addSubview:view];
30-
}
31-
3230
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex {
31+
RCTAssert(_reactSubview == nil, @"[RNTModalView]: can only have one react subview");
32+
3333
[super insertReactSubview:subview atIndex:atIndex];
3434
[self.mountingHelper updateChildrenTransaction:^{
3535
[self.touchHandler attachToView:subview];
3636
[self.modalViewController addReactSubview:subview];
37+
self.reactSubview = subview;
3738
}];
3839
}
3940

4041
- (void)removeReactSubview:(UIView *)subview
4142
{
43+
RCTAssert(subview == _reactSubview, @"[RNTModalView]: cannot remove view other than react subview");
44+
4245
[super removeReactSubview:subview];
4346
dispatch_async(dispatch_get_main_queue(), ^{
4447
[self.touchHandler detachFromView:subview];
4548
[self.mountingHelper unmountIfNeeded];
4649
[subview removeFromSuperview];
50+
self.reactSubview = nil;
4751
});
4852
}
4953

@@ -57,11 +61,10 @@ - (void) didSetProps: (NSArray<NSString*>*)changedProps {
5761
}];
5862
}
5963

60-
// Props
64+
#pragma mark - RNTModalViewControllerDelegate
6165

62-
- (void)setAnimationType:(NSString *)animationType
63-
{
64-
_animationType = animationType;
66+
- (void)boundsDidChange:(CGRect)newBounds {
67+
[self.bridge.uiManager setSize:newBounds.size forView:self.reactSubview];
6568
}
6669

6770
@end

0 commit comments

Comments
 (0)