react native 学习笔记----封装Android的原生组件

前端之家收集整理的这篇文章主要介绍了react native 学习笔记----封装Android的原生组件前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

参考文档官方版:Native UI Components

中文版:原生UI组件

上面的文档介绍了facebook 开发小组,如何封装原生组件ImageView给js调用,但是没有具体的实例。本文以封装原生TextView为例,一步一步的实现一个简单示例。

提供原生视图很简单:

  1. 创建一个ViewManager的子类(或者更常见的,SimpleViewManage的派生类)。
  2. 实现createViewInstance方法
  3. 导出视图的属性设置器:使用@ReactProp(或@ReactPropGroup)注解。
  4. 把这个视图管理类注册到应用程序包的createViewManagers里。
  5. 实现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 = @H_502_185@"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()}

编译并运行,就可以看到下面的效果

猜你在找的React相关文章