一. 创建RN项目, 并用Android Studio打开项目中的android文件夹
二. 考虑把组件传到npm, 所以就新建一个Android Library,名为CQTextView
RN与android交互_2.pngRN与android交互_1.png
然后进行以下配置
1. 为原生模块添加React Native依赖. 在cqtextview对应的build.gradle的dependencies里面添加以下代码
compile "com.facebook.react:react-native:+"
- 为 app 添加原生模块依赖,在 app 对应的 build.gradle的dependencies里面添加如下代码
compile project(':cqtextview')
三. 编写原生模块
- 创建一个类CQTextViewManager 继承自SimoleViewManager
package com.example.cukiy.cqtextview;
import android.widget.TextView;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
public class CQTextViewManager extends SimpleViewManager {
// 重写getName()方法, 返回的字符串就是RN中使用该组件的名称
@Override
public String getName() {
return "CQTextView";
}
// 重写createViewInstance()方法,在里面写原生界面. 这里简单写一个TextView
@Override
protected TextView createViewInstance(ThemedReactContext reactContext) {
TextView textView = new TextView(reactContext);
return textView;
}
// 其中,可以通过@ReactProp(或@ReactPropGroup)注解来导出属性的设置方法。
// 该方法有两个参数,第一个参数是泛型View的实例对象,第二个参数是要设置的属性值。
// 方法的返回值类型必须为void,而且访问控制必须被声明为public。
// 组件的每一个属性的设置都会调用Java层被对应ReactProp注解的方法
@ReactProp(name = "text")
public void setText(TextView textView, String text) {
textView.setText(text);
}
@ReactProp(name = "textSize")
public void setTextSize(TextView textView, int size) {
textView.setTextSize(size);
}
}
- 注册原生模块. 创建一个实现于ReactPackage的类CQTextViewPackage
package com.example.cukiy.cqtextview;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
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;
public class CQTextViewPackage implements ReactPackage {
// 必须重写该方法
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
// 这个方法@Override注解会报错 所以就注释了
// @Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
//必须重写该方法. 将我们创建的TextView注册到视图管理列表中
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new CQTextViewManager()
);
}
}
- 在MainApplication中注册原生组件
import com.example.cukiy.cqtextview.CQTextViewPackage;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
......
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new CQTextViewPackage() // 注册原生模块
);
}
......
};
}
四. 在React Native中使用
- 在React Native中新建一个js文件名为RNTextView,获取并导出原生组件
import React, {Component} from 'react';
import {requireNativeComponent, View} from 'react-native';
import PropTypes from 'prop-types';
let NativeTextView = requireNativeComponent("CQTextView",RNTextView);
export default class RNTextView extends Component {
static propTypes = {
// name必须与原生组件getName()方法中返回的字符串一致
name:"CQTextView",
propTypes:{
style: View.propTypes.style,
text:PropTypes.string,
textSize:PropTypes.number,
...View.propTypes //包含默认的View的属性,如果没有这句会报‘has no propType for native prop’错误
}
};
render() {
return <NativeTextView {...this.props} />;
}
}
- 使用
import React, { Component } from 'react';
import {
Platform,
View,
} from 'react-native';
import RNTextView from './RNTextView';
export default class App extends Component<{}> {
render() {
return (
<View style={{ flex:1,backgroundColor:'#eee',justifyContent:'center',alignItems:'center'}}>
<RNTextView style={{marginTop:20,height:50,width:300,backgroundColor:'cyan'}}
text="使用原生TextView"
textSize={20}/>
</View>
);
}
}
RN与android交互_3.png
五. 开发中会有这样的需求. 当原生组件状态改变时, 需要给RN组件传一些值让RN组件也作出相应的改变. 例如上面原生TextView点击之后给RN传值, RN获取值之后alert出来. 下面就实现这样一个功能
- 在原生代码CQTextViewManager中,在创建textView时添加点击事件.
@Override
protected TextView createViewInstance(ThemedReactContext reactContext) {
final TextView textView = new TextView(reactContext);
// 给textView添加点击事件
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 下面这块代码会主动向RN发送事件通知
WritableMap event = Arguments.createMap();
// 在事件中添加string参数
event.putString("msg", "点击了原生TextView");
// 在事件中添加int参数
event.putInt("index", 123);
// 获取组件所在的context
ReactContext reactContext = (ReactContext) textView.getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
textView.getId(), // 原生视图和RN视图通过getId()关联在一起
"topChange", // 事件名topChange在JavaScript端映射到onChange回调属性上 event); } }); return textView; }
- 上面已经向RN发送了通知, 将会调用RN中该组件的onChange方法. 在RNTextView文件中设置onChange方法
import React from 'react';
import {requireNativeComponent, View} from 'react-native';
import PropTypes from 'prop-types';
let NativeTextView = requireNativeComponent("CQTextView",RNTextView);
export default class RNTextView React.Component {
static propTypes = {
// name必须与原生组件getName()方法中返回的字符串一致
name:"CQTextView",
propTypes:{
style: View.propTypes.style,
onClick:PropTypes.func,
text:PropTypes.string,
textSize:PropTypes.number,
...View.propTypes //包含默认的View的属性,如果没有这句会报‘has no propType for native prop’错误
};
}
_onClick(event: Event) {
if(this.props.onClick) {
this.props.onClick(event.native.msg,event.native.index)
}
}
render() {
return <NativeTextView {...this.props} onChange={this._onClick.bind(this)} />;
}
}
- 现在就可以在组件中使用onClick回调属性了
render() {
return (
<View style={{ flex:1,backgroundColor:'#eee',justifyContent:'center',alignItems:'center'}}>
<RNTextView style={{marginTop:20,height:50,width:300,backgroundColor:'cyan'}}
text="使用原生TextView"
textSize={20}
onClick={(msg,index)=>alert(msg + ' --- ' + index)}/>
</View>
);
}
点击之后弹出提示
RN与android交互_4.png
网友评论