RN調(diào)用iOS原生組件

創(chuàng)建RCTViewManager子類來創(chuàng)建和管理原生視圖
原生視圖都需要被一個(gè)RCTViewManager的子類來創(chuàng)建和管理。

這些管理器在功能上有些類似“視圖控制器”,但它們本質(zhì)上都是單例 - React Native只會(huì)為每個(gè)管理器創(chuàng)建一個(gè)實(shí)例。

它們創(chuàng)建原生的視圖并提供給RCTUIManager,RCTUIManager則會(huì)反過來委托它們在需要的時(shí)候去設(shè)置和更新視圖的屬性。RCTViewManager還會(huì)代理視圖的所有委托,并給JavaScript發(fā)回對應(yīng)的事件。
提供原生視圖步驟如下:
首先創(chuàng)建一個(gè)子類 —— 命名規(guī)范為“視圖名稱+Manager”. 視圖名稱可以加上自己的前綴,這里最好避免使用RCT前綴,除非你想給官方pull request
添加RCT_EXPORT_MODULE()標(biāo)記宏 —— 讓模塊接口暴露給JavaScript
實(shí)現(xiàn)-(UIView *)view方法 —— 創(chuàng)建并返回組件視圖
封裝屬性及傳遞事件
下面先貼出完整的代碼,然后會(huì)對屬性和事件進(jìn)行進(jìn)一步的解說。
TestScrollViewManager.h

#import "RCTViewManager.h"

@interface TestScrollViewManager : RCTViewManager

@end

TestScrollViewManager.m

#import "TestScrollViewManager.h"
#import "TestScrollView.h"      //第三方組件的頭文件

#import "RCTBridge.h"           //進(jìn)行通信的頭文件
#import "RCTEventDispatcher.h"  //事件派發(fā),不導(dǎo)入會(huì)引起Xcode警告

@interface TestScrollViewManager() <SDCycleScrollViewDelegate>

@end

@implementation TestScrollViewManager

//  標(biāo)記宏(必要)
RCT_EXPORT_MODULE()

//  事件的導(dǎo)出,onClickBanner對應(yīng)view中擴(kuò)展的屬性
RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)

//  通過宏RCT_EXPORT_VIEW_PROPERTY完成屬性的映射和導(dǎo)出
RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);

RCT_EXPORT_VIEW_PROPERTY(imageURLStringsGroup, NSArray);

RCT_EXPORT_VIEW_PROPERTY(autoScroll, BOOL);

- (UIView *)view
{
    //  實(shí)際組件的具體大小位置由js控制
    TestScrollView *testScrollView = [TestScrollView cycleScrollViewWithFrame:CGRectZero delegate:self placeholderImage:nil];
    //  初始化時(shí)將delegate指向了self
    testScrollView.pageControlStyle = SDCycleScrollViewPageContolStyleClassic;
    testScrollView.pageControlAliment = SDCycleScrollViewPageContolAlimentCenter;
    return testScrollView;
}

/**
 *  當(dāng)事件導(dǎo)出用到 sendInputEventWithName 的方式時(shí),會(huì)用到
- (NSArray *) customDirectEventTypes {
    return @[@"onClickBanner"];
}
 */

#pragma mark SDCycleScrollViewDelegate
/**
 *  banner點(diǎn)擊
 */
- (void)cycleScrollView:(TestScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index
{
//    這也是導(dǎo)出事件的方式,不過好像是舊方法了,會(huì)有警告
//    [self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
//                                                   body:@{@"target": cycleScrollView.reactTag,
//                                                          @"value": [NSNumber numberWithInteger:index+1]
//                                                        }];

    if (!cycleScrollView.onClickBanner) {
        return;
    }

    NSLog(@"oc did click %li", [cycleScrollView.reactTag integerValue]);

    //  導(dǎo)出事件
    cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,
                                    @"value": [NSNumber numberWithInteger:index+1]});
}

// 導(dǎo)出枚舉常量,給js定義樣式用
- (NSDictionary *)constantsToExport
{
    return @{
             @"SDCycleScrollViewPageContolAliment": @{
                     @"right": @(SDCycleScrollViewPageContolAlimentRight),
                     @"center": @(SDCycleScrollViewPageContolAlimentCenter)
                     }
             };
}

//  因?yàn)檫@個(gè)類繼承RCTViewManager,實(shí)現(xiàn)RCTBridgeModule,因此可以使用原生模塊所有特性
//  這個(gè)方法暫時(shí)沒用到
RCT_EXPORT_METHOD(testResetTime:(RCTResponseSenderBlock)callback) {
    callback(@[@(234)]);
}

@end

屬性

RCT_EXPORT_VIEW_PROPERTY(autoScrollTimeInterval, CGFloat);

通過宏RCT_EXPORT_VIEW_PROPERTY完成屬性的映射和導(dǎo)出。

CGFloat為autoScrollTimeInterval的OC數(shù)據(jù)類型,轉(zhuǎn)化成js則對應(yīng)number。
React Native用RCTConvert來在JavaScript和原生代碼之間完成類型轉(zhuǎn)換。

支持的默認(rèn)轉(zhuǎn)換類型(部分)如下:

string (NSString)
number (NSInteger, float, double, CGFloat, NSNumber)
boolean (BOOL, NSNumber)
array (NSArray) 包含本列表中任意類型
map (NSDictionary) 包含string類型的鍵和本列表中任意類型的值

如果轉(zhuǎn)換無法完成,會(huì)產(chǎn)生一個(gè)“紅屏”的報(bào)錯(cuò)提示,這樣你就能立即知道代碼中出現(xiàn)了問題。如果一切進(jìn)展順利,上面這個(gè)宏就已經(jīng)包含了導(dǎo)出屬性的全部實(shí)現(xiàn)。
ps:更復(fù)雜的類型轉(zhuǎn)換,則涉及到MKCoordinateRegion類型,本文沒做應(yīng)用,具體可參考官方文檔例子。

事件

js和原生之間需要有事件的交互,例如,在原生實(shí)現(xiàn)的代理或者點(diǎn)擊事件,js也需要實(shí)時(shí)獲取到此類事件時(shí),就需要利用事件進(jìn)行交互。

事件的實(shí)現(xiàn)方式有以下兩種:
通過sendInputEventWithName實(shí)現(xiàn)

  1. 實(shí)現(xiàn)customDirectEventTypes,返回自定義的事件名數(shù)組(on開頭才有效)
- (NSArray *) customDirectEventTypes {
 return @[@"onClickBanner"];
}
  1. sendInputEventWithName實(shí)現(xiàn)事件調(diào)用(reactTag用于實(shí)例的區(qū)分)
[self.bridge.eventDispatcher sendInputEventWithName:@"onClickBanner"
                                               body:@{@"target": cycleScrollView.reactTag,
                                                      @"value": [NSNumber numberWithInteger:index+1]

通過RCTBubblingEventBlock實(shí)現(xiàn)

  1. 在封裝的View中添加RCTBubblingEventBlock的block屬性(on開頭才有效)
@property (nonatomic, copy) RCTBubblingEventBlock onClickBanner;
  1. 在Manager類中通過宏RCT_EXPORT_VIEW_PROPERTY完成Block屬性的映射和導(dǎo)出
RCT_EXPORT_VIEW_PROPERTY(onClickBanner, RCTBubblingEventBlock)
  1. 實(shí)現(xiàn)事件調(diào)用(reactTag用于實(shí)例的區(qū)分)
cycleScrollView.onClickBanner(@{@"target": cycleScrollView.reactTag,@"value": [NSNumber numberWithInteger:index+1]});

通過上面兩種方式封裝好的事件,在js中可以直接利用同名函數(shù)調(diào)用即可(后面會(huì)展示)。

不過關(guān)于事件這塊,挺多都沒完全弄懂,希望有大神引導(dǎo)引導(dǎo),比如為什么只能定義on開頭、如何自定義、如何事件數(shù)據(jù)源的回調(diào)等等。。。

樣式
因?yàn)槲覀兯械囊晥D都是UIView的子類,大部分的樣式屬性應(yīng)該直接就可以生效。有些屬性定義,需要用到枚舉,則可以利用通過原生傳遞來的常數(shù)方式來實(shí)現(xiàn),具體實(shí)現(xiàn)如下:

// 導(dǎo)出枚舉常量,給js定義樣式用
- (NSDictionary *)constantsToExport
{
    return @{
             @"SDCycleScrollViewPageContolAliment": @{
                     @"right": @(SDCycleScrollViewPageContolAlimentRight),
                     @"center": @(SDCycleScrollViewPageContolAlimentCenter)
                     }
             };
}

在js中調(diào)用則如下:

//  首先獲取到常量
var TestScrollViewConsts = require('react-native').UIManager.TestScrollView.Constants;

//  調(diào)用
<TestScrollView style={styles.container} 
    pageControlAliment = {TestScrollViewConsts.SDCycleScrollViewPageContolAliment.right}
 />

ps: 一部分組件會(huì)希望使用自己定義的默認(rèn)樣式,例如UIDatePicker希望自己的大小是固定的。比如大小用原生默認(rèn)大小,這個(gè)例子具體可以參考官方文檔的樣式模塊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容