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

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

参考文档官方版:Native UI Components

中文版:原生UI组件

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

提供原生视图很简单:

@H_502_10@
  • 创建一个ViewManager的子类(或者更常见的,SimpleViewManage的派生类)。
  • 实现createViewInstance方法
  • 导出视图的属性设置器:使用@ReactProp(或@ReactPropGroup)注解。
  • 把这个视图管理类注册到应用程序包的createViewManagers里。
  • 实现JavaScript模块。
  • 在开始之前,先创建一个工程,命令如下:

    react-native init NativeView

    第一步. 创建@H_301_54@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()}

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

    猜你在找的React相关文章