
正文
ReactNative如何在JS中引用原生自定义控件(rn变化太快,网上很多教程有坑,这个我研究后可用,特意分享)
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
直接写一个Demo例子,有相关功底的肯定明白,会对特别的地方进行提醒,本文基于https://blog.csdn.net/lintcgirl/article/details/53489490,但是按此链接文章不可用。
首先是JAVA部分:
import com.facebook.react.ReactActivity;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "RNMyTest";
}
}
import android.app.Application; import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import com.rnmytest.view.AppReactPackage; import java.util.Arrays;
import java.util.List; public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
} @Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new AppReactPackage()
);
} @Override
protected String getJSMainModuleName() {
return "index";
}
}; @Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
} @Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
第一坑,之前的项目可能创建时间太久,ReactApplication完全无法引用,后面我是重新新建一个demo测试后能成功导入,各种百度google无法解决这个方案,如有能解决的朋友请告诉我。
下面是自定义的view
import com.facebook.react.ReactPackage;
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; /**
* Created by bingmingli on 2018/6/8.
*/ public class AppReactPackage implements ReactPackage { @Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
} // @Override
// public List<Class<? extends JavaScriptModule>> createJSModules() {
// return Collections.emptyList();
// } @Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new CircleManager()
);
}
}
第二坑:注释部分的方法在新版本已经去除了
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.Log;
import android.view.View; import com.facebook.react.uimanager.PixelUtil; public class CircleView extends View {
private final String TAG = "CircleView";
private Paint mPaint; // 画笔
private float mRadius; // 圆的半径 public CircleView(Context context) {
super(context);
mPaint = new Paint();
mPaint.setColor(0xAA000000);
} /**
* 设置圆的半径
* @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); // 画一个半径为100px的圆
Log.d(TAG, "绘图");
}
}
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp; /**
* Created by bingmingli on 2018/6/8.
*/ public class CircleManager extends SimpleViewManager<CircleView> { /**
* 设置js引用名
*/
@Override
public String getName() {
return "MCircle";
} /**
* 创建UI组件实例
*/
@Override
protected CircleView createViewInstance(ThemedReactContext reactContext) {
return new CircleView(reactContext);
} /**
* 传输半径参数
*/
@ReactProp(name = "radius")
public void setRadius(CircleView view, Integer radius) {
view.setRadius(radius);
}
}
下面是JS部分:
circle.js
import React, { Component } from 'react';
import {
View,
requireNativeComponent
} from 'react-native';
import PropTypes from 'prop-types'
// const RCTCircle = requireNativeComponent('MCircle', {
// propTypes: {
// radius: PropTypes.number,
// ...View.propTypes // 包含默认的View的属性
// },
// });
// module.exports=RCTCircle;
var iface = {
name: 'MCircle',
propTypes: {
radius: PropTypes.number,
...View.propTypes
},
};
module.exports = requireNativeComponent('MCircle', iface);
第三坑:PropTypes的导入方式为import PropTypes from 'prop-types'
第四坑:...View.propTypes这个必须有,不然自己的属性不能识别
第五坑:iface里面的name 与 requireNativeComponent的第一个参数需要一致,很多教程这里不一致,导致找不到这个原生view
App.js
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View
} from 'react-native';
import MCircle from './circle';
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' +
'Cmd+D or shake for dev menu',
android: 'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
export default class App extends Component<Props> {
render() {
return (
<View>
<MCircle
style={{width: 100, height: 100}}
radius={50}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
提醒:导入的view必须名字也一致,这不用多说了






