美文网首页React-Native随笔
RN原生模块的调用基础(五)

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

作者: sleeping_7e17 | 来源:发表于2018-05-03 15:16 被阅读239次

    假设现在我们要画一个圆,当然,你可以用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

    相关文章

      网友评论

        本文标题:RN原生模块的调用基础(五)

        本文链接:https://www.haomeiwen.com/subject/jwnkrftx.html