参考文档官方版:Native UI Components
中文版:原生UI组件
上面的文档介绍了facebook 开发小组,如何封装原生组件ImageView给js调用,但是没有具体的实例。本文以封装原生TextView为例,一步一步的实现一个简单示例。
提供原生视图很简单:
- 创建一个ViewManager的子类(或者更常见的,
SimpleViewManage 的派生类)。
- 实现
createViewInstance 方法。
- 导出视图的属性设置器:使用
@ReactProp (或@ReactPropGroup )注解。
- 把这个视图管理类注册到应用程序包的
createViewManagers 里。
- 实现JavaScript模块。
在开始之前,先创建一个工程,命令如下:
react-native init NativeView
第一步. 创建ViewManager 的子类MyTextViewManager
第二步.实现方法createViewInstance
第三步. 通过@ReactPropGroup )注解来导出属性的设置方法
上面三步中MyTextViewManager的整个代码如下:
public class MyTextViewManager extends SimpleViewManager<TextView> {
@Override
public String getName() {
return "MyTextView";
}
@Override
protected TextView createViewInstance(ThemedReactContext reactContext) {
TextView textView = new TextView(reactContext);
return textView;
}
@ReactProp(name = "text")
public void setText(TextView view,String text) {
view.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);
}
@ReactProp(name = "isAlpha",defaultBoolean = false) public void setTextAlpha(TextView view,boolean isAlpha) {
if (isAlpha) {
view.setAlpha(0.5f); }
} }
第四步:注册MyTextViewManager。
创建类MyReactPackage,实现ReactPackage的方法createViewManager,在该方法中注册上面的组件MyTextViewManager。实现ReactPackage时,需要实现这三个方法,学过导入原生模块部分时我们应该很熟悉了。封装的原生模块放在createNativeModules里,封装的原生UI组件放在createViewManagers里。需要注意的是剩下的最后一个方法createJSModules里默认是返回null,要改成返回空集合,否则编译时会报错。
代码如下:
public class MyReactPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new MyTextViewManager()
);
}
}
MyReactPackage还需要在MainApplication.java文件的getPackages方法中提供。这个文件位于你的react-native应用文件夹的android目录中。具体路径是: android/app/src/main/java/com/your-app-name/MainApplication.java. @Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),new MyReactPackage()
);
}
第五步:实现对应的JS模块。
最后一步就是创建JavaScript模块并且定义Java和JavaScript之间的接口层。大部分过程都由React底层的Java和JavaScript代码来完成,你所需要做的就是通过来描述属性的类型。
propTypes
新建一个MyTextView.js文件。代码如下:
import { PropTypes } from 'react';
import {requireNativeComponent,View} from'react-native';
var myTextView ={
name:'MyTextView', propTypes:{
text:PropTypes.string, textSize:PropTypes.number, textColor:PropTypes.number, isAlpha:PropTypes.bool,
...View.propTypes // 包含默认的View的属性
}
}
module.exports =requireNativeComponent('MyTextView',myTextView);
最后:然后你就可以在js代码中引用刚才的组件了,引用例子:
import React,{ Component } from 'react'; import { AppRegistry, StyleSheet, Text, View } from 'react-native'; var MyTextView = require('./MyTextView'); class NativeView extends Component { render() { return ( <View style={styles.container}> <View style={styles.outView}> <MyTextView style={styles.myTextView} text={"Welcome you Andy!"} textSize={25} /> </View> </View> ); } } const styles = StyleSheet.create({ container: { justifyContent:'center', alignItems:'center', flex: 1, backgroundColor: '#F5FCFF', }, outView:{ borderWidth:2, }, myTextView:{ width:300, height:50, }); AppRegistry.registerComponent('NativeView',() => NativeView);
事件
现在我们已经知道了怎么导出一个原生视图组件,并且我们可以在JS里很方便的控制它了。不过我们怎么才能处理来自用户的事件,譬如用户的点击?当一个原生事件发生的时候,它应该也能触发JavaScript端视图上的事件,这两个视图会依据getId()而关联在一起。
在MyTextViewManager中,修改createViewInstance方法。代码如下:
@Override
protected TextView createViewInstance(final ThemedReactContext reactContext) {
final TextView textView = new TextView(reactContext);
textView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v,MotionEvent event) {
if(event.getAction()== MotionEvent.ACTION_DOWN){
WritableMap nativeEvent= Arguments.createMap();
nativeEvent.putString("message","MyMessage");
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
textView.getId(),"topChange",nativeEvent
);
return true;
}else{
return false;
}
}
});
return textView;
}
这是在创建的view实例中,当发生本地事件时进行事件注册。这个事件名topChange
在JavaScript端映射到onChange
回调属性上,这个映射关系是固定的被官方写在UIManagerModuleConstants.java
文件里了。这个回调会被原生事件执行,
然后我们通常会封装组建里构造一个类似的API,修改上面的MyTextView.js文件,完整代码如下
import { PropTypes } from 'react'; import {requireNativeComponent,View} from'react-native'; var myTextView ={ name:'MyTextView', propTypes:{ text:PropTypes.string, ...View.propTypes // 包含默认的View的属性 } } //module.exports =requireNativeComponent('MyTextView',myTextView); var RCTMyView=requireNativeComponent('MyTextView',myTextView); import React,{ Component } from 'react'; class MyView extends Component{ constructor(){ super(); this._onChange = this._onChange.bind(this); } _onChange(event:Event){ if(!this.props.onChangeMessage){ return; } if(event.nativeEvent.message === 'MyMessage'){ this.props.onChangeMessage(); return; } } render(){ return<RCTMyView {...this.props} onChange = {this._onChange}/> } } MyView.propTypes = { onChangeMessage:React.PropTypes.func, } module.exports = MyView;
这里用MyView对myTextView进行了一次封装。注意到在MyView里为onChange绑定了_onChange方法,在这个方法里我们会调用一个预定义为函数的onChangeMessage。而之前已经在native端将topChange绑定了原生的onTouch事件,topChange又会映射到JS端的onChange属性,这样最后当原生的onTouch事件发生时,就会调用JS端定义的onChangeMessage函数,就实现了两端事件的互动。其实onTouch事件对应到onChange属性后就已经实现了事件绑定,写onChangeMessage是为了示例展示而已。 现在只需在index.android.js文件中添加几行代码就可以看到效果了
只需为上面的index.android.js文件添加几行代码即可。
添加一个函数
_onButtonPress(){ alert("haha,you pressed me"); this.setState({ text:"bind event successful!" }); }
再给MyTextView添加一个属性onChangeMessage={()=>this._onButtonPress()}
编译并运行,就可以看到下面的效果 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|