React Native中使用Android原生组件

一. 创建RN项目, 并用Android Studio打开项目中的android文件夹

二. 考虑把组件传到npm, 所以就新建一个Android Library,名为CQTextView

RN与android交互_2.png

RN与android交互_1.png

然后进行以下配置
1. 为原生模块添加React Native依赖. 在cqtextview对应的build.gradle的dependencies里面添加以下代码

compile "com.facebook.react:react-native:+"
  1. 为 app 添加原生模块依赖,在 app 对应的 build.gradle的dependencies里面添加如下代码
compile project(':cqtextview')

三. 编写原生模块

  1. 创建一个类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);
    }
}
  1. 注册原生模块. 创建一个实现于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 createNativeModules(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    // 这个方法@Override注解会报错  所以就注释了
    //  @Override
    public List> createJSModules() {
        return Collections.emptyList();
    }

    //必须重写该方法. 将我们创建的TextView注册到视图管理列表中
    @Override
    public List createViewManagers(ReactApplicationContext reactContext) {
        return Arrays.asList(
                new CQTextViewManager()
        );
    }
}
  1. 在MainApplication中注册原生组件
import com.example.cukiy.cqtextview.CQTextViewPackage;

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    
    ......

    @Override
    protected List getPackages() {
      return Arrays.asList(
          new MainReactPackage(),
          new CQTextViewPackage() // 注册原生模块
      );
    }

    ......

  };
}

四. 在React Native中使用

  1. 在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 ;
  }
}
  1. 使用
import React, { Component } from 'react';
import {
  Platform,
  View,
} from 'react-native';

import RNTextView from './RNTextView';

export default class App extends Component<{}> {
  render() {
    return (
        

              
        

    );
  }
}
RN与android交互_3.png

五. 开发中会有这样的需求. 当原生组件状态改变时, 需要给RN组件传一些值让RN组件也作出相应的改变. 例如上面原生TextView点击之后给RN传值, RN获取值之后alert出来. 下面就实现这样一个功能

  1. 在原生代码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; }
  1. 上面已经向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 ;
  }
}
  1. 现在就可以在组件中使用onClick回调属性了
render() {
   return (
      

        alert(msg + ' --- ' + index)}/>
      

  );
}

点击之后弹出提示


RN与android交互_4.png

你可能感兴趣的:(React Native中使用Android原生组件)