Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#import "RCTDefaultReactNativeFactoryDelegate.h"
#import <ReactCommon/RCTHost.h>
#import <React/RCTViewController.h>
#import "RCTAppSetupUtils.h"
#import "RCTDependencyProvider.h"
#if USE_THIRD_PARTY_JSC != 1
Expand All @@ -28,7 +29,7 @@ - (NSURL *_Nullable)sourceURLForBridge:(nonnull RCTBridge *)bridge

- (UIViewController *)createRootViewController
{
return [UIViewController new];
return [RCTViewController new];
}

- (RCTBridge *)createBridgeWithDelegate:(id<RCTBridgeDelegate>)delegate launchOptions:(NSDictionary *)launchOptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
* LICENSE file in the root directory of this source tree.
*/

#import <UIKit/UIKit.h>
#import <React/RCTViewController.h>

@protocol RCTFabricModalHostViewControllerDelegate <NSObject>
- (void)boundsDidChange:(CGRect)newBounds;
@end

@interface RCTFabricModalHostViewController : UIViewController
@interface RCTFabricModalHostViewController : RCTViewController

@property (nonatomic, weak) id<RCTFabricModalHostViewControllerDelegate> delegate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
* LICENSE file in the root directory of this source tree.
*/

#import <UIKit/UIKit.h>
#import <React/RCTViewController.h>

#ifndef RCT_REMOVE_LEGACY_ARCH

__attribute__((deprecated("This API will be removed along with the legacy architecture.")))
@interface RCTModalHostViewController : UIViewController
@interface RCTModalHostViewController : RCTViewController

@property (nonatomic, copy) void (^boundsDidChangeBlock)(CGRect newBounds);

Expand Down
42 changes: 42 additions & 0 deletions packages/react-native/React/Views/RCTViewController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@protocol RCTViewControllerAppearanceListener <NSObject>

@optional
- (void)reactViewControllerDidAppear:(UIViewController *)viewController animated:(BOOL)animated;
- (void)reactViewControllerDidDisappear:(UIViewController *)viewController animated:(BOOL)animated;

@end

@interface UIViewController (RCTViewControllerAppearance)

@property (nonatomic, assign, readonly) BOOL reactViewControllerIsVisible;

- (void)reactAddViewControllerAppearanceListener:(id<RCTViewControllerAppearanceListener>)listener;
- (void)reactRemoveViewControllerAppearanceListener:(id<RCTViewControllerAppearanceListener>)listener;

/**
* Call from `viewDidAppear:` / `viewDidDisappear:` in UIViewController subclasses
* that cannot inherit from RCTViewController.
*/
- (void)reactNotifyViewControllerDidAppear:(BOOL)animated;
- (void)reactNotifyViewControllerDidDisappear:(BOOL)animated;

@end

/**
* UIViewController subclass that forwards appearance events to registered listeners.
*/
@interface RCTViewController : UIViewController
@end

NS_ASSUME_NONNULL_END
90 changes: 90 additions & 0 deletions packages/react-native/React/Views/RCTViewController.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import "RCTViewController.h"

#import <objc/runtime.h>

static void RCTSetViewControllerIsVisible(UIViewController *viewController, BOOL isVisible)
{
objc_setAssociatedObject(
viewController, @selector(reactViewControllerIsVisible), @(isVisible), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@implementation UIViewController (RCTViewControllerAppearance)

- (NSHashTable<id<RCTViewControllerAppearanceListener>> *)reactViewControllerAppearanceListeners
{
NSHashTable<id<RCTViewControllerAppearanceListener>> *listeners =
objc_getAssociatedObject(self, @selector(reactViewControllerAppearanceListeners));
if (!listeners) {
listeners = [NSHashTable weakObjectsHashTable];
objc_setAssociatedObject(
self, @selector(reactViewControllerAppearanceListeners), listeners, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return listeners;
}

- (BOOL)reactViewControllerIsVisible
{
return [objc_getAssociatedObject(self, @selector(reactViewControllerIsVisible)) boolValue];
}

- (void)reactAddViewControllerAppearanceListener:(id<RCTViewControllerAppearanceListener>)listener
{
[[self reactViewControllerAppearanceListeners] addObject:listener];

if (self.reactViewControllerIsVisible &&
[listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) {
[listener reactViewControllerDidAppear:self animated:NO];
}
}

- (void)reactRemoveViewControllerAppearanceListener:(id<RCTViewControllerAppearanceListener>)listener
{
[[self reactViewControllerAppearanceListeners] removeObject:listener];
}

- (void)reactNotifyViewControllerDidAppear:(BOOL)animated
{
RCTSetViewControllerIsVisible(self, YES);

for (id<RCTViewControllerAppearanceListener> listener in [self reactViewControllerAppearanceListeners].allObjects) {
if ([listener respondsToSelector:@selector(reactViewControllerDidAppear:animated:)]) {
[listener reactViewControllerDidAppear:self animated:animated];
}
}
}

- (void)reactNotifyViewControllerDidDisappear:(BOOL)animated
{
RCTSetViewControllerIsVisible(self, NO);

for (id<RCTViewControllerAppearanceListener> listener in [self reactViewControllerAppearanceListeners].allObjects) {
if ([listener respondsToSelector:@selector(reactViewControllerDidDisappear:animated:)]) {
[listener reactViewControllerDidDisappear:self animated:animated];
}
}
}

@end

@implementation RCTViewController

- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self reactNotifyViewControllerDidAppear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self reactNotifyViewControllerDidDisappear:animated];
}

@end
4 changes: 2 additions & 2 deletions packages/react-native/React/Views/RCTWrapperViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/

#import <UIKit/UIKit.h>
#import <React/RCTViewController.h>

@class RCTWrapperViewController;

@interface RCTWrapperViewController : UIViewController
@interface RCTWrapperViewController : RCTViewController

- (instancetype)initWithContentView:(UIView *)contentView NS_DESIGNATED_INITIALIZER;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@
#import <React/RCTVibration.h>
#import <React/RCTVibrationPlugins.h>
#import <React/RCTView.h>
#import <React/RCTViewController.h>
#import <React/RCTViewManager.h>
#import <React/RCTViewUtils.h>
#import <React/RCTVirtualTextShadowView.h>
Expand Down
Loading