如何在 React Native 中呈现原生 UIViewController?(不能只使用 UIView)

IT技术 javascript ios objective-c reactjs react-native
2021-04-27 02:27:53

我正在尝试在我的 React Native 应用程序中使用 ABNewPersonViewController。这是它在 Objective-C 中的使用方式:

ABNewPersonViewController *picker = [[ABNewPersonViewController alloc] init];
picker.newPersonViewDelegate = self;

UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:picker];
[self presentViewController:navigation animated:NO completion:nil];

我将如何在 React Native 中做到这一点?我无法编写桥接 UI 组件,因为它是 UIViewController,而不是 UIView。

请不要告诉我重新实现它😟

3个回答

这就是最终对我有用的东西。

创建Contact.h:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
#import "RCTBridgeModule.h"

@interface CreateContact : NSObject <ABNewPersonViewControllerDelegate, RCTBridgeModule>

@end

创建Contact.m:

#import "CreateContact.h"
#import "AppDelegate.h"

@implementation CreateContact

RCT_EXPORT_MODULE(CreateContact);


RCT_EXPORT_METHOD(presentContact) {

    dispatch_async(dispatch_get_main_queue(), ^{
        ABNewPersonViewController *picker = [[ABNewPersonViewController alloc] init];
        picker.newPersonViewDelegate = self;
        UINavigationController* contactNavigator = [[UINavigationController alloc] initWithRootViewController:picker];
        AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        [delegate.window.rootViewController presentViewController:contactNavigator animated:NO completion:nil];
    });
}

- (void)newPersonViewController:(ABNewPersonViewController *)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person
{
    [newPersonViewController dismissViewControllerAnimated:YES completion:nil];
}
@end

本教程有更多细节:http : //moduscreate.com/leverage-existing-ios-views-react-native-app/

我会在实施将信息反馈给 RN 的最佳方式时进行更新。

你想实现一个桥接的 UI 组件,它挂载一个空的 UIView,主要负责呈现你的 UIViewController。这种技术最简单的例子是在 RCTModalHostView 中;查看源代码

值得注意的是,React Native 在 UIView 上定义了一个类别,该类别添加了一个名为的属性,该属性reactViewController会爬升视图层次结构以找到最近的 UIViewController。使用这个 UIViewController 来展示你的自定义视图控制器:

- (void)didMoveToWindow
{
  [super didMoveToWindow];

  if (!_isPresented && self.window) {
    [self.reactViewController presentViewController:_customViewController
                                           animated:NO
                                         completion:nil];
    _isPresented = YES;
  }
}

您实际上可以做的是将 UIViewController 作为子视图添加到关键窗口视图控制器,但仍然将 UIViewController 的视图作为子视图添加到本机module视图中,因此它包含在本机module视图的框​​架和生命周期中,而无需在本机module视图的生命周期之外呈现 UIViewController 本身 ->

UIWindow *window = (UIWindow*)[[UIApplication sharedApplication] keyWindow];
[window.rootViewController addChildViewController:_myViewController];
_myViewController.view.frame = self.superview.frame;
[self addSubview:_myViewController.view];
[_myViewController didMoveToParentViewController:window.rootViewController];

这是完整的实现->

在你的 MyViewManager.m 添加

#import "RCTUIManager.h"

@interface MyViewManager ()

@end

@implementation MyViewManager

RCT_EXPORT_MODULE()

- (UIView*)view
{
    return [[MyView alloc] init];
}

@end

并在您的 MyView.h 添加

#if __has_include("React/RCTViewManager.h")
#import "React/RCTViewManager.h"
#else
#import "RCTViewManager.h"
#endif

#import <UIKit/UIKit.h>
#import <AVKit/AVKit.h>

@interface MyView : UIView

@property(nonatomic, strong)UIViewController* myViewController;

@end

并在您的 MyView.m 添加

#import "MyView.h"
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>

@implementation MyView

- (instancetype)init
{
    self = [super init];
    return self;
}

- (void)dealloc
{

}

- (void)layoutSubviews
{
    [super layoutSubviews];

    if (_myViewController != nil) {
        _myViewController.view.frame = self.frame;
    }
}

- (void)removeFromSuperview {
    if (_myViewController != nil) {
         [_myViewController willMoveToParentViewController:nil];
         [_myViewController.view removeFromSuperview];
         [_myViewController removeFromParentViewController];
         _myViewController = nil;
         [super removeFromSuperview];
    }
}

-(void)addViewControllerAsSubView
{
    _myViewController = [UIViewController new];
    UIWindow *window = (UIWindow*)[[UIApplication sharedApplication] keyWindow];
    [window.rootViewController addChildViewController:_myViewController];
    _myViewController.view.frame = self.superview.frame;
    [self addSubview:_myViewController.view];
    [_myViewController didMoveToParentViewController:window.rootViewController];
}