ReactNative如何在JS中引用原生自定义控件(rn变化太快,网上很多教程有坑,这个我研究后可用,特意分享)

Posted lee0oo0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReactNative如何在JS中引用原生自定义控件(rn变化太快,网上很多教程有坑,这个我研究后可用,特意分享)相关的知识,希望对你有一定的参考价值。

直接写一个Demo例子,有相关功底的肯定明白,会对特别的地方进行提醒,本文基于https://blog.csdn.net/lintcgirl/article/details/53489490,但是按此链接文章不可用。

 

首先是JAVA部分:

 1 import com.facebook.react.ReactActivity;
 2 
 3 public class MainActivity extends ReactActivity {
 4 
 5     /**
 6      * Returns the name of the main component registered from javascript.
 7      * This is used to schedule rendering of the component.
 8      */
 9     @Override
10     protected String getMainComponentName() {
11         return "RNMyTest";
12     }
13 }

 

 1 import android.app.Application;
 2 
 3 import com.facebook.react.ReactApplication;
 4 import com.facebook.react.ReactNativeHost;
 5 import com.facebook.react.ReactPackage;
 6 import com.facebook.react.shell.MainReactPackage;
 7 import com.facebook.soloader.SoLoader;
 8 import com.rnmytest.view.AppReactPackage;
 9 
10 import java.util.Arrays;
11 import java.util.List;
12 
13 public class MainApplication extends Application implements ReactApplication {
14 
15   private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
16     @Override
17     public boolean getUseDeveloperSupport() {
18       return BuildConfig.DEBUG;
19     }
20 
21     @Override
22     protected List<ReactPackage> getPackages() {
23       return Arrays.<ReactPackage>asList(
24           new MainReactPackage(),
25               new AppReactPackage()
26       );
27     }
28 
29     @Override
30     protected String getJSMainModuleName() {
31       return "index";
32     }
33   };
34 
35   @Override
36   public ReactNativeHost getReactNativeHost() {
37     return mReactNativeHost;
38   }
39 
40   @Override
41   public void onCreate() {
42     super.onCreate();
43     SoLoader.init(this, /* native exopackage */ false);
44   }
45 }

第一坑,之前的项目可能创建时间太久,ReactApplication完全无法引用,后面我是重新新建一个demo测试后能成功导入,各种百度google无法解决这个方案,如有能解决的朋友请告诉我。

 

下面是自定义的view

 1 import com.facebook.react.ReactPackage;
 2 import com.facebook.react.bridge.NativeModule;
 3 import com.facebook.react.bridge.ReactApplicationContext;
 4 import com.facebook.react.uimanager.ViewManager;
 5 import java.util.Arrays;
 6 import java.util.Collections;
 7 import java.util.List;
 8 
 9 /**
10  * Created by bingmingli on 2018/6/8.
11  */
12 
13 public class AppReactPackage implements ReactPackage {
14 
15     @Override
16     public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
17         return Collections.emptyList();
18     }
19 
20 //    @Override
21 //    public List<Class<? extends JavaScriptModule>> createJSModules() {
22 //        return Collections.emptyList();
23 //    }
24 
25     @Override
26     public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
27         return Arrays.<ViewManager>asList(
28                 new CircleManager()
29         );
30     }
31 }

第二坑:注释部分的方法在新版本已经去除了

 

 1 import android.content.Context;
 2 import android.graphics.Canvas;
 3 import android.graphics.Paint;
 4 import android.util.Log;
 5 import android.view.View;
 6 
 7 import com.facebook.react.uimanager.PixelUtil;
 8 
 9 public class CircleView extends View {
10     private final String TAG = "CircleView";
11     private Paint mPaint; // 画笔
12     private float mRadius;  // 圆的半径
13 
14     public CircleView(Context context) {
15         super(context);
16         mPaint = new Paint();
17         mPaint.setColor(0xAA000000);
18     }
19 
20     /**
21      * 设置圆的半径
22      * @param radius
23      */
24     public void setRadius(Integer radius) {
25         /**
26          * 由于JS传过的数字是dip单位,需要转换为实际像素
27          * 使用com.facebook.react.uimanager包中的PixelUtil,进行转换
28          */
29         mRadius = PixelUtil.toPixelFromDIP(radius);
30         invalidate();
31     }
32 
33     @Override
34     protected void onDraw(Canvas canvas) {
35         super.onDraw(canvas);
36         canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); // 画一个半径为100px的圆
37         Log.d(TAG, "绘图");
38     }
39 }

 

 1 import com.facebook.react.uimanager.SimpleViewManager;
 2 import com.facebook.react.uimanager.ThemedReactContext;
 3 import com.facebook.react.uimanager.annotations.ReactProp;
 4 
 5 /**
 6  * Created by bingmingli on 2018/6/8.
 7  */
 8 
 9 public class CircleManager extends SimpleViewManager<CircleView> {
10 
11     /**
12      * 设置js引用名
13      */
14     @Override
15     public String getName() {
16         return "MCircle";
17     }
18 
19     /**
20      * 创建UI组件实例
21      */
22     @Override
23     protected CircleView createViewInstance(ThemedReactContext reactContext) {
24         return new CircleView(reactContext);
25     }
26 
27     /**
28      * 传输半径参数
29      */
30     @ReactProp(name = "radius")
31     public void setRadius(CircleView view, Integer radius) {
32         view.setRadius(radius);
33     }
34 }

 

下面是JS部分:

circle.js

 1 import React, { Component } from ‘react‘;
 2 import {
 3   View,
 4   requireNativeComponent
 5 } from ‘react-native‘;
 6 
 7 import PropTypes from ‘prop-types‘
 8 // const RCTCircle = requireNativeComponent(‘MCircle‘, {
 9 //   propTypes: {
10 //     radius: PropTypes.number,
11 //     ...View.propTypes // 包含默认的View的属性
12 //   },
13 // });
14 // module.exports=RCTCircle;
15 
16 var iface = {
17   name: ‘MCircle‘,
18   propTypes: {
19     radius: PropTypes.number,
20     ...View.propTypes
21   },
22 };
23  
24 module.exports = requireNativeComponent(‘MCircle‘, iface);

第三坑:PropTypes的导入方式为import PropTypes from ‘prop-types‘
第四坑:...View.propTypes这个必须有,不然自己的属性不能识别
第五坑:iface里面的name 与 requireNativeComponent的第一个参数需要一致,很多教程这里不一致,导致找不到这个原生view

 

App.js

 1 import React, { Component } from ‘react‘;
 2 import {
 3   Platform,
 4   StyleSheet,
 5   Text,
 6   View
 7 } from ‘react-native‘;
 8 
 9 import MCircle from ‘./circle‘;
10 
11 const instructions = Platform.select({
12   ios: ‘Press Cmd+R to reload,\n‘ +
13     ‘Cmd+D or shake for dev menu‘,
14   android: ‘Double tap R on your keyboard to reload,\n‘ +
15     ‘Shake or press menu button for dev menu‘,
16 });
17 
18 export default class App extends Component<Props> {
19   render() {
20     return (
21                 <View>
22                     <MCircle
23                           style={{width: 100, height: 100}}
24                           radius={50}
25                     />
26                 </View>
27             ); 
28   }
29 }
30 
31 const styles = StyleSheet.create({
32   container: {
33     flex: 1,
34     justifyContent: ‘center‘,
35     alignItems: ‘center‘,
36     backgroundColor: ‘#F5FCFF‘,
37   },
38   welcome: {
39     fontSize: 20,
40     textAlign: ‘center‘,
41     margin: 10,
42   },
43   instructions: {
44     textAlign: ‘center‘,
45     color: ‘#333333‘,
46     marginBottom: 5,
47   },
48 });

提醒:导入的view必须名字也一致,这不用多说了

 

以上是关于ReactNative如何在JS中引用原生自定义控件(rn变化太快,网上很多教程有坑,这个我研究后可用,特意分享)的主要内容,如果未能解决你的问题,请参考以下文章

ReactNative 桥接原生原子组件

如何使用 Jest 测试导入自定义原生模块的 React Native 组件?

使用 Swift 反应原生自定义 UI 组件:如何在事件中访问 reactTag

在 React Native Android 上定义自定义原生事件

从其他原生代码访问 React Native 模块

如何在原生基础中更改主题?