#import "RNSScreenStackHostComponentView.h" #import #import #import #import #import #import #import #import "RNSDefines.h" #import "Swift-Bridging.h" namespace react = facebook::react; @interface RNSScreenStackHostComponentView () @end @implementation RNSScreenStackHostComponentView { RNSStackController *_Nonnull _controller; NSMutableArray *_Nonnull _reactSubviews; bool _hasModifiedReactSubviewsInCurrentTransaction; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self initState]; } return self; } - (void)initState { _controller = [[RNSStackController alloc] initWithStackHostComponentView:self]; _hasModifiedReactSubviewsInCurrentTransaction = false; _reactSubviews = [NSMutableArray new]; } - (void)didMoveToWindow { RCTAssert(_controller != nil, @"[RNScreens] Controller must not be nil while attaching to window"); [self reactAddControllerToClosestParent:_controller]; } - (void)reactAddControllerToClosestParent:(UIViewController *)controller { if (!controller.parentViewController) { UIView *parentView = (UIView *)self.reactSuperview; while (parentView) { if (parentView.reactViewController) { [parentView.reactViewController addChildViewController:controller]; [self addSubview:controller.view]; [controller didMoveToParentViewController:parentView.reactViewController]; break; } parentView = (UIView *)parentView.reactSuperview; } return; } } RNS_IGNORE_SUPER_CALL_BEGIN - (nonnull NSMutableArray *)reactSubviews { return _reactSubviews; } RNS_IGNORE_SUPER_CALL_END - (nonnull RNSStackController *)stackController { RCTAssert(_controller != nil, @"[RNScreens] Controller must not be nil"); return _controller; } #pragma mark - RCTViewComponentViewProtocol - (void)mountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { RCTAssert( [childComponentView isKindOfClass:RNSStackScreenComponentView.class], @"[RNScreens] Attempt to mount child of unsupported type: %@, expected %@", childComponentView.class, RNSStackScreenComponentView.class); auto *childScreen = static_cast(childComponentView); childScreen.stackHost = self; [_reactSubviews insertObject:childScreen atIndex:index]; _hasModifiedReactSubviewsInCurrentTransaction = true; } - (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index { RCTAssert( [childComponentView isKindOfClass:RNSStackScreenComponentView.class], @"[RNScreens] Attempt to unmount child of unsupported type: %@, expected %@", childComponentView.class, RNSStackScreenComponentView.class); auto *childScreen = static_cast(childComponentView); [_reactSubviews removeObject:childScreen]; childScreen.stackHost = nil; _hasModifiedReactSubviewsInCurrentTransaction = true; } + (react::ComponentDescriptorProvider)componentDescriptorProvider { return react::concreteComponentDescriptorProvider(); } + (BOOL)shouldBeRecycled { // There won't be tens of instances of this component usually & it's easier for now. // We could consider enabling it someday though. return NO; } #pragma mark - RCTMountingTransactionObserving - (void)mountingTransactionWillMount:(const facebook::react::MountingTransaction &)transaction withSurfaceTelemetry:(const facebook::react::SurfaceTelemetry &)surfaceTelemetry { _hasModifiedReactSubviewsInCurrentTransaction = false; [_controller reactMountingTransactionWillMount]; } - (void)mountingTransactionDidMount:(const facebook::react::MountingTransaction &)transaction withSurfaceTelemetry:(const facebook::react::SurfaceTelemetry &)surfaceTelemetry { if (_hasModifiedReactSubviewsInCurrentTransaction) { [_controller setNeedsUpdateOfChildViewControllers]; } [_controller reactMountingTransactionDidMount]; } @end Class RNSScreenStackHostCls(void) { return RNSScreenStackHostComponentView.class; }