废话不多说,直接上干货
网上已经有很多将OC控件导出给RN侧使用的办法了,这里不做过多的赘述,此次旨在导出一个Swift控件,并且通过一些骚办法绕过或者减少使用OC桥接文件
首先,先将需自己的Swift控件继承自RCTView,如图我定义了一个自定义的Swift键盘
public class KeyboardView: RCTView {
override init(frame: CGRect) {
super.init(frame: frame)
......
}
}
第二步,定义一些想在RN侧提供的属性,需要注意的是,需要使用@objc修饰,并且属性需要使用on开头(约定),类型为RCTDirectEventBlock,该类型为RN标签中方法,同时定义一些RN标签的属性,我们本次重点为触发这些属性,下图为对应的属性与方法在RN标签中对应的属性名和方法的引用。
public class KeyboardView: RCTView {
@objc var onViewState: RCTDirectEventBlock? = nil
@objc var onViewClose: RCTDirectEventBlock? = nil
@objc var onShowState: CGFloat = 0 {
...
}
override init(frame: CGRect) {
super.init(frame: frame)
......
}
}
<KeyboardView
onShowState={1}
onViewState={() => {}}
onViewClose={() => {}}
/>
第三步,定义一个swift文件,做为导出我们控件给RN使用的Manager管理层
按照如下写法,继承自RCTViewManager,同时使用@objc注解修饰想要导出的Swift控件名,至此一个原生控件就已经导出成功了,需要记住@objc中修饰的CustomKeyboardView就是后续导出的时候的模块名
import Foundation
import React
@objc(CustomKeyboardView)
public class XXXKeyboardViewManager: RCTViewManager {
public override func view() -> UIView {
return KeyboardView()
}
public override static func requiresMainQueueSetup() -> Bool {
return true
}
}
第四步,创建一个和刚才Manager同名的.m文件,用来导出属性和方法名以及组件名称,需要注意的是RCT_EXTERN_MODULE是导出模块的名称,第一个参数则是刚刚swiftManager中被@objc修饰的地方
//
// XXXKeyboardViewManager.m
// XXXKeyboardManager
//
// Created by wangchuaichuai on 2024/4/7.
//
#import <Foundation/Foundation.h>
#import <React/RCTViewManager.h>
@interface RCT_EXTERN_MODULE(CustomKeyboardView, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(onViewState, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onViewClose, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onShowState, CGFloat);
@end
如上一个Swift控件就导出成功了,但是在OC中导出一个方法需要在.m文件中使用OC语法进行编写(对于我这种对OC一知半解的人来说不友好),所以采用Swift中的一种骚办法来触发对应的方法——didSet
在上述控件中,我导出了一个自定义属性onShowState,我们通过设置其didSet属性来进行触发方法,这里只做简单的举例,onShowState传入一个number类型,来在Swift这边触发onShowState的didSet方法进行方法的执行,通过这种方法,可以绕过在OC文件中编写对应方法的步骤,转而在比较友好的Swift文件中进行编写,而直接使用Swift导出RN控件的实现也是比较麻烦的,所以在项目中采用了这种比较骚气的方法绕过OC代码。
public class KeyboardView: RCTView {
@objc var onViewState: RCTDirectEventBlock? = nil
@objc var onViewClose: RCTDirectEventBlock? = nil
@objc var onShowState: CGFloat = 0 {
didSet {
switch onShowState {
case 1:
self?.functionAdd()
self?.onViewState?(["selectString": "所选的值"])
case 2:
self?.functionDelete()
default:
self?.functionClose()
}
}
}
}
import { requireNativeComponent } from "react-native"
class Keyboard extends React.Component {
render() {
return <KeyboardCustom {...this.props} />
}
}
const KeyboardCustom = requireNativeComponent("CustomKeyboardView", KeyboardView)
export default KeyboardView;
// 使用
<KeyboardView
onShowState={1}
onViewState={(e: string) => {
// 为Swift控件代码中回调的值的使用
console.log(e.nativeEvent.selectString)
}}
/>