1. 程式人生 > >ReactNative如何在JS中引用原生自定義控件(rn變化太快,網上很多教程有坑,這個我研究後可用,特意分享)

ReactNative如何在JS中引用原生自定義控件(rn變化太快,網上很多教程有坑,這個我研究後可用,特意分享)

not net boolean button nag instr 自定義控件 col 朋友

直接寫一個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變化太快,網上很多教程有坑,這個我研究後可用,特意分享)