React-Native随笔

RN原生模块的调用基础(五)

2018-05-03  本文已影响239人  sleeping_7e17

假设现在我们要画一个圆,当然,你可以用js自己去实现,但是今天要讲的并不是js去实现圆,而是在Native端去写一个View去暴露给js调用,ok,我们废话少说,进入正题

暴露一个简单控件给js调用分为以下几个步骤:
1.自定义一个View控件
2.自定义一个Manager实现SimpleViewManager
3.将自定义的Manager注册进Package
4.js调用

自定义View控件相信android老司机们早已驾轻就熟,不再啰嗦,直接看代码

public class CircleView extends View {
    private static final String TAG = "CircleView";
    private Paint mPaint;
    private float mRadius;

    public CircleView(Context context) {
        super(context);
        mPaint = new Paint();
    }

    /**
     * 设置圆的背景色
     * @param color
     */
    public void setColor(Integer color) {
        mPaint.setColor(color); // 设置画笔颜色
        invalidate();   // 更新画板
    }

    /**
     * 设置圆的半径
     * @param radius
     */
    public void setRadius(Integer radius) {
        /**
         * 由于JS传过的数字是dip单位,需要转换为实际像素
         * 使用com.facebook.react.uimanager包中的PixelUtil,进行转换
         */
        mRadius = PixelUtil.toPixelFromDIP(radius);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);;
    }

下面开始自定义Manager:

public class CircleManager extends SimpleViewManager<CircleView> {
    @Override
    public String getName() {
        return "MCircle";
    }

    /**
     * 创建UI组件实例
     * @param reactContext
     * @return CircleView
     */
    @Override
    protected CircleView createViewInstance(ThemedReactContext reactContext) {
        return new CircleView(reactContext);
    }

    /**
     * 传输背景色参数
     * @param view
     * @param color
     */
    @ReactProp(name = "color")
    public void setColor(CircleView view, Integer color) {
        view.setColor(color);
    }

    /**
     * 传输半径参数
     * @param view
     * @param radius
     */
    @ReactProp(name = "radius")
    public void setRadius(CircleView view, Integer radius) {
        view.setRadius(radius);
    }
}

注意这里的getName方法的返回值要与js里一致,这个文章后面再详细说明,先有个大致的概念,同时还需要注意的是@ReactProp这个注解

OK,我们有了Manager,现在去注册到package,很简单

public class CommPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new CommonModule(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        List<ViewManager> views = new ArrayList<>();
        views.add(new CircleManager());
        return views;
    }
}

注意到这里的createViewManagers不再返回一个emptyList,而是把CircleManager给add进去了

最后,我们写一下js代码
首先我们需要写一个Circle.js

import React, { Component } from 'react';
import { requireNativeComponent, View, processColor } from 'react-native';  //processColor=>字符Color转换为数字
import PropTypes from 'prop-types';

const MCircle = requireNativeComponent('MCircle', {
  propTypes: {
      color: PropTypes.number,
      radius: PropTypes.number,
      ...View.propTypes // 包含默认的View的属性
  },
});

class Circle extends Component {
      static propTypes = {
        radius: PropTypes.number,
        color: PropTypes.string, // 这里传过来的是string
        ...View.propTypes // 包含默认的View的属性
      }

      render() {
        const { style, radius, color } = this.props;

        return (
          <MCircle
            style={style}
            radius={radius}
            color={processColor(color)}
          />
        );
      }
}

module.exports = Circle;

注意这边的requireNativeComponent有两个参数:第一个参数是MCircle,这个名字要与上面的CircleManager的getName返回值保持一致;第二个参数约定了属性的一些类型,可以看到有一个number类型的color属性,一个number类型的radius属性,这两个属性是怎么对应到Native端的,这就要说到上面的@ReactProp注解,我们截取下之前的代码

/**
     * 传输背景色参数
     * @param view
     * @param color
     */
    @ReactProp(name = "color")
    public void setColor(CircleView view, Integer color) {
        view.setColor(color);
    }

    /**
     * 传输半径参数
     * @param view
     * @param radius
     */
    @ReactProp(name = "radius")
    public void setRadius(CircleView view, Integer radius) {
        view.setRadius(radius);
    }

可以看到@ReactProp注解有个name的key,他的value值对应的就是Circle.js里propTypes声明的属性,每当js那边设置color属性,这个setColor的方法就会自动调用,这样就把js的参数传递到了native

最后我们改下index.js

'use strict'
import React, { Component} from 'react';
import { AsyncStorage,NativeModules,ToastAndroid } from 'react-native';
import {
  AppRegistry,
  StyleSheet,
  Text,
  Image,
  View
} from 'react-native';

import Circle from './Circle';

let title = 'React Native界面';

export default class YRNTest extends Component {
    /**
    * Callback 通信方式
    */
    callbackComm(msg) {
        NativeModules.CommonModule.rnCallNativeFromCallback(msg,(result) => {
             ToastAndroid.show("CallBack收到消息:" + result, ToastAndroid.SHORT);
        })
    }

    /**
    * Promise 通信方式
    */
    promiseComm(msg) {
        NativeModules.CommonModule.rnCallNativeFromPromise(msg).then(
            (result) =>{
                ToastAndroid.show("Promise收到消息:" + result, ToastAndroid.SHORT)
            }
        ).catch((error) =>{console.log(error)});
    }

  render() {
    return (
        <View style={styles.container}>
            <Circle
                style={{width: 100, height: 100}}
                color="#25c5f7"
                radius={50}
            />
        </View>
//      <View style={styles.container}>
//        <Text style={styles.welcome} >
//            {title}
//        </Text>
//        <Text style={styles.welcome} onPress={this.callbackComm.bind(this,'你好啊,android')}>
//             Callback通信方式
//        </Text>
//        <Text style={styles.welcome} onPress={this.promiseComm.bind(this,'你好啊,android')}>
//             Promise通信方式
//        </Text>
//      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#FFFFFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  }
});

AppRegistry.registerComponent('YRNTest', () => YRNTest);

添加import Circle from './Circle';
render里改为

<View style={styles.container}>
            <Circle
                style={{width: 100, height: 100}}
                color="#25c5f7"
                radius={50}
            />
</View>
运行工程,大功告成,附上截图 1525331564339.jpg
上一篇下一篇

猜你喜欢

热点阅读