React Native封装Android原生控件

来源:互联网 发布:linux vi 文件末尾 编辑:程序博客网 时间:2024/05/22 09:44

第一步:

我们首先要创建一个RN项目:

react-native init 你的项目名

第二步:

是用Android studio打开RN项目中的Android项目。
在新建一个文件夹用于存放我们封装的控件,结构如下:

这里写图片描述

第三步:

创建ViewManager,比如TextViewManager,代码如下:

import android.graphics.Color;import android.util.Log;import android.view.View;import android.widget.TextView;import com.facebook.react.bridge.Arguments;import com.facebook.react.bridge.ReactContext;import com.facebook.react.bridge.ReactMethod;import com.facebook.react.bridge.ReadableMap;import com.facebook.react.bridge.WritableMap;import com.facebook.react.uimanager.SimpleViewManager;import com.facebook.react.uimanager.ThemedReactContext;import com.facebook.react.uimanager.annotations.ReactProp;import com.facebook.react.uimanager.events.RCTEventEmitter;/** * Created by sujialong on 2017/9/1. */public class TextViewManager extends SimpleViewManager<TextView> {    @Override    public String getName() {        return "CustomTextView";    }    @Override    protected TextView createViewInstance(ThemedReactContext reactContext) {        final TextView textView = new TextView(reactContext);//        final ThemedReactContext myContext = reactContext;        //注册点击事件        textView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                WritableMap event = Arguments.createMap();                event.putString("message", "MyMessage哈哈哈--自定义");                ReactContext reactContext = (ReactContext)textView.getContext();                reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(                        textView.getId(),                        "topChange",                        event);            }        });        return textView;    }    @ReactProp(name="text")    public void setText(TextView textView,String text){        textView.setText(text);    }    @ReactProp(name="textSize")    public void setTextSize(TextView view,float fontSize){        view.setTextSize(fontSize);    }    @ReactProp(name = "textColor",defaultInt = Color.BLACK)    public void setTextColor(TextView view,int textColor){        view.setTextColor(textColor);    }}

1.getName方法用于js端导出时,使用的控件名称。
2.createViewInstance方法用于创建控件与初始化状态。
3.使用@ReactProp注解的方法,是将js端传入的属性值导出,并且给控件设置该属性值。

@ReactProp
该注解可以传入两个参数:
1. name:js端使用时传入的参数名,必传。
2. defaultBoolean:设置默认值,可选,其他选项:defaultInt,defaultFloat。这些参数必须是对应的基础类型的值(也就是boolean,int, float),这些值会被传递给setter方法,以免JavaScript端某些情况下在组件中移除了对应的属性。

第四步:

注册ViewManager,新建一个class,名为ReactViewPackage,在这个class里面加入以下代码:

import com.facebook.react.ReactPackage;import com.facebook.react.bridge.NativeModule;import com.facebook.react.bridge.ReactApplicationContext;import com.facebook.react.uimanager.ViewManager;import java.util.Arrays;import java.util.Collections;import java.util.List;/** * Created by sujialong on 2017/9/1. */public class ReactViewPackage implements ReactPackage {    @Override    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {        return Arrays.<NativeModule>asList(                new ToastViewManager(reactContext)        );    }    @Override    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {        return Arrays.<ViewManager>asList(                new TextViewManager()        );    }}

这里面需要我们实现ReactPackage的两个方法:createViewManagers,createNativeModules。以前还有一个叫做createJSModules的方法,现在被移除掉了。其中,createNativeModules是用来添加原生模块的,比如:Toast等。createViewManagers是用来添加原生的UI组件的。
我们第一个创建的TextView是UI组件,所以我们将TextViewManager添加到createViewManagers中,如果没有引入原生模块,可以将createNativeModules方返回空数组:

@Override    public List<NativeModule> createViewManagers(ReactApplicationContext reactContext) {        return Collections.emptyList();    }

第五步:

在项目的MainApplication.java文件的getPackages方法中添加,我们封装的原生模块:

@Override    protected List<ReactPackage> getPackages() {      return Arrays.<ReactPackage>asList(          new MainReactPackage(),              new ReactViewPackage()      );    }

ok,到这一步我们基本的封装已经完毕。

第六步:

需要我们在js端导出所封装的原生组件,如下:

import React, {PureComponent,PropTypes} from 'react';import {requireNativeComponent,View} from 'react-native';const CustomTextView = {    name:"CustomTextView",    propTypes:{        "text":PropTypes.string,        "textSize":PropTypes.number,        "textColor":PropTypes.number,        ...View.propTypes    }}const RCTCustomTextView = requireNativeComponent('CustomTextView',CustomTextView,{    nativeOnly: {onChange: true}});export default class MyView extends PureComponent {    _onChange = (event: Event) => {        const onChangeMessage = this.props.onChangeMessage;        onChangeMessage && onChangeMessage(event.nativeEvent);    }    render() {        return (            <RCTCustomTextView {...this.props} onChange={this._onChange}/>        );    }}MyView.propTypes = {    onChangeMessage:PropTypes.func,};

这里,由于我们是封装的TextView,需要使用requireNativeComponent在原生代码中引用。requireNativeComponent通常接受两个参数,第一个参数是原生视图的名字,也就是我们在ViewManager中使用getName方法定义的名字,而第二个参数是一个描述组件接口的对象。组件接口应当声明一个友好的name,用来在调试信息中显示;组件接口还必须声明propTypes字段,用来对应到原生视图上。这个propTypes还可以用来检查用户使用View的方式是否正确。

第六步:

使用所封装好的组件:

import React, { Component } from 'react';import {  AppRegistry,  StyleSheet,  Text,  View,  DeviceEventEmitter} from 'react-native';import CustomTextView from './src/CustomTextView';
export default class CustomRnView extends Component {  render() {    return (      <View style={styles.container}>        <CustomTextView            style={styles.myTextView}            text="我是封装的原生组件"            textSize={15}            onChangeMessage={(msg)=>{              CustomToastView.show("点到我了----",CustomToastView.SHORT);              CustomToastView.getNativeClass(this._getNativeClass);              this._getNativePromise();            }}/>      </View>    );  }}const styles = StyleSheet.create({  container: {    flex: 1,    justifyContent: 'center',    alignItems: 'center',    backgroundColor: '#F5FCFF',  },  myTextView:{    width:300,    height:100,  },});

第七步:

在项目的根目录下,运行:

react-native run-android

成功啦!!!

这里写图片描述

第八步:为原生模块添加方法

要给js端调用的方法,需要使用@ReactMethod注解:

@ReactMethodpublic void show(String message, int duration){     Toast.makeText(getReactApplicationContext(), message, duration).show();}

在js端如下调用:

import CustomToastView from './src/CustomToastView';CustomToastView.show("message",CustomToastView.SHORT);

第九步:为原生代码添加回调函数

1.使用Callback:

import com.facebook.react.bridge.Callback;//使用回调函数@ReactMethodpublic void getNativeClass(Callback callback){    callback.invoke("使用回调函数");}

在js端如下调用:

import CustomToastView from './src/CustomToastView';CustomToastView.getNativeClass((res) => {    alert(res);});

2.使用Promise:

//使用promise回调    @ReactMethod    public void getArguments(Boolean isResolve,Promise promise){        WritableMap map = Arguments.createMap();        map.putString("name", "Arno");        map.putString("age", "25");        if(isResolve){            promise.resolve(map);        }else{            promise.reject(map.toString());        }    }

在js端使用:

import CustomToastView from './src/CustomToastView';CustomToastView.getArguments(true)        .then((res) => {            console.log("getArguments---success");            console.log(res);        },(error)=>{          console.log("getArguments---error");          console.log(res);        });

3.给JS发送事件

private static final String TestEventName = "TestEventName";//发送事件,js端使用事件监听接收    public void setEvent(){        WritableMap params = Arguments.createMap();        params.putString("name", "Jack");        reactContext_                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)                .emit(TestEventName, params);    }

js端使用DeviceEventEmitter设置监听接收:

import {  DeviceEventEmitter} from 'react-native';DeviceEventEmitter.addListener(CustomToastView.TestEventName,(res)=>{        console.log("我是事件监听");        console.log(res);    });

大家也可以先看一下官方文档:http://reactnative.cn/docs/0.47/native-modules-android.html#content

遇到的问题:

1.在js端导出组件后使用的时候,报错:

这里写图片描述

解决方案:
在requireNativeComponent的第二个参数内,也就是描述组件属性的时候,在propTypes内,加入…View.propTypes:

这里写图片描述

因为,在这里我只描述了我规定的属性字段,RN其实自己会添加很多默认的属性,使用扩展符合并就可以了。

最后附上源码:https://github.com/1035901787/CustomRnView

原创粉丝点击