RN 封装 Android原生组件
背景
当在React Native暂时未提供部分原生功能或者模块,我们需要复用部分原生代码时,比如复用一个原生方法,此时就需要将原生方法进行封装,暴露出一个接口来让React-Native调用。
步骤
官网样例
以封装一个自适应字体大小的文本框为例,实现了设置文本、字体大小、可缩小到的最小字体大小、字体颜色、是否中划线、是否下划线、是否加粗、文字对齐方式、文本超出限制时省略号的位置、文本最大行数。
创建一个RN工程
命令行:react-native init 项目名
打开RN工程里的Android项目
创建ViewManager
实现getName方法
getName方法返回的名字在js端引用我们的控件时使用
实现createViewInstance方法
视图是在createViewInstance方法中创建的,视图应该在其默认状态下初始化,任何属性都将通过后续调用来设置updateView
导出给RN使用的属性
要导出给JavaScript使用的属性,需要申明带有@ReactProp(或@ReactPropGroup)注解的设置方法。
方法的第一个参数 view是要修改属性的视图实例,第二个参数 text是要设置的属性值。
方法的返回值类型必须为void,而且访问控制必须被声明为public。
@ReactProp注解必须包含一个字符串类型的参数name。这个参数指定了对应属性在RN端的名字。
class ReactAutoResizeTextViewManager : SimpleViewManager<AutoResizeTextView>() {companion object {const val REACT_CLASS = "REACTAutoResizeTextView"}override fun getName(): String {return REACT_CLASS}override fun createViewInstance(reactContext: ThemedReactContext): AutoResizeTextView {return AutoResizeTextView(reactContext)}@ReactProp(name = "text")fun setText(autoResizeTextView: AutoResizeTextView, text: String) {autoResizeTextView.setText(text)}@ReactProp(name = "textSize")fun setTextSize(autoResizeTextView: AutoResizeTextView, textSize: Float) {autoResizeTextView.setTextSize(textSize)}@ReactProp(name = "gravity")fun setTextGravity(autoResizeTextView: AutoResizeTextView, gravity: String) {autoResizeTextView.setTextGravity(gravity)}@ReactProp(name = "textColor")fun setTextColor(autoResizeTextView: AutoResizeTextView, textColor: String) {autoResizeTextView.setTextColor(textColor)}@ReactProp(name = "maxLines")fun setMaxLines(autoResizeTextView: AutoResizeTextView, maxLines: Int) {autoResizeTextView.setMaxLine(maxLines)}@ReactProp(name = "minTextSize")fun setMinTextSize(autoResizeTextView: AutoResizeTextView, minTextSize: Float) {autoResizeTextView.setMinTextSize(minTextSize)}@ReactProp(name = "underLine")fun setUnderLine(autoResizeTextView: AutoResizeTextView, underLine: Boolean) {autoResizeTextView.setUnderLine(underLine)}@ReactProp(name = "middleLine")fun setMiddleLine(autoResizeTextView: AutoResizeTextView, middleLine: Boolean) {autoResizeTextView.setMiddleLine(middleLine)}@ReactProp(name = "ellipsize")fun setEllipsize(autoResizeTextView: AutoResizeTextView, ellipsize: String) {autoResizeTextView.setEllipsize(ellipsize)}@ReactProp(name = "bold")fun setBold(autoResizeTextView: AutoResizeTextView, bold: Boolean) {autoResizeTextView.setTextStyle(bold)}}
注册ViewManager
新建ReactViewPackage类,实现ReactPackage的两个方法:createNativeModules,createViewManagers。
createNativeModules是用来添加原生模块的,比如:Toast等。createViewManagers是用来添加原生的UI组件的。
将我们创建的ReactAutoResizeTextViewManager添加到createViewManagers中,如果没有引入原生模块,可以将createNativeModules方返回空数组
class AutoResizeTextViewPackage : ReactPackage {override fun createNativeModules(reactContext: ReactApplicationContext): MutableList<NativeModule> {return Collections.emptyList()}override fun createViewManagers(reactContext: ReactApplicationContext): MutableList<ViewManager<*, *>> {return mutableListOf(ReactAutoResizeTextViewManager())}}
注册Package
在项目的MainApplication.java文件的getPackages方法中添加我们封装的原生模块
@Overrideprotected List<ReactPackage> getPackages() {List<ReactPackage> packages = new PackageList(this).getPackages();// Packages that cannot be autolinked yet can be added manually here, for example:packages.add(new AutoResizeTextViewPackage());return packages;}
在js端导出所封装的原生组件
requireNativeComponent通常接受两个参数,第一个参数是原生视图的名字,而第二个参数是一个描述组件接口的对象。组件接口应当声明一个友好的name,用来在调试信息中显示;组件接口还必须声明propTypes字段,用来对应到原生视图上。这个propTypes还可以用来检查用户使用View的方式是否正确。
import {requireNativeComponent,View} from 'react-native'import {PropTypes} from 'prop-types'const mReactAutoResizeTextView = {name: "REACTAutoResizeTextView",propTypes:{"text":PropTypes.string,"maxLines":PropTypes.number,...View.propTypes}}export default requireNativeComponent('REACTAutoResizeTextView',mReactAutoResizeTextView)
使用封装好的组件
import React, {Component } from 'react';import {AppRegistry,StyleSheet,Text,View,DeviceEventEmitter} from 'react-native';import ReactAutoResizeTextView from './ReactAutoResizeTextView';class mView extends Component {render() {return (<View style={styles.container}><ReactAutoResizeTextViewstyle={styles.mAutoResizeTextView}text="曾经沧海难为水,除却巫山不是云。取次花丛懒回顾,半缘修道半缘君。"textSize={15}//文字大小middleLine={true}//是否中划线underLine={false}//是否下划线gravity="center"//文字对齐方式,默认左对齐ellipsize="middle"//文字超出限制长度后省略号位置,默认在末尾minTextSize={6}//可缩小到的最小字体大小,若不设,则可以无限缩小bold={true}//是否加粗textColor="#FF0000"//字体颜色maxLines={1}//文字最大行数/></View>)}};const styles = StyleSheet.create({container:{flex: 1,justifyContent: 'center',alignItems: 'center',backgroundColor: 'white',},mAutoResizeTextView:{width:300,height:300,},mTitle:{width:300,height:50,marginBottom:30,textAlign:'center',color:'black'}});AppRegistry.registerComponent('MyNativePackage', () => mView);
运行项目
命令行:react-native run-android