当react-native的UI组件不能满足需求时,可以考虑在原生自定UI组件,让RN调用.使用原生UI所考虑的问题:
一.原生UI被调用;
二.修改原生UI属性值;
三.捕捉原生UI的响应;
四.RN向原生UI组件发消息;
下面贴上代码,逐步分析,实现:
1.在原生里自定义UI,创建本地模块封装.
package com.firstapp.widget;
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;
/**
* Description:
* Created by song on /7/23.
* email:bjay0613@
*/
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();
}
/**
* 设置圆的半径
* @param color
*/
public void setColor(Integer color) {
mPaint.setColor(color); // 设置画笔颜色
invalidate(); // 更新画板
}
/**
* 设置圆的半径
* @param radius
*/
public void setRadius(Integer radius) {
mRadius = PixelUtil.toPixelFromDIP(radius);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
Log.d(TAG, "绘制一个半径为100px的圆");
}
public void onReciveNativeEvent(){
}
}
2 : 创建ViewManager 继承 SimpleViewManager<CircleView>
package com.firstapp.widget.manager;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.WritableMap;
import com.mon.MapBuilder;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.firstapp.widget.CircleView;
import java.util.Map;
import javax.annotation.Nullable;
/**
* Description:
* Created by song on /7/23.
* email:bjay0613@
*/
public class CircleViewManager extends SimpleViewManager<CircleView> implements LifecycleEventListener {
private static final String EVENT_NAME_ONCLICK = "onClick";
private static final String HANDLE_METHOD_NAME = "handleTask"; // 交互方法名
private static final int HANDLE_METHOD_ID = 1; // 交互命令ID
private ThemedReactContext mContext;
/**
* 设置js引用名
*/
@Override
public String getName() {
return "MCircle";
}
/**
* 创建UI组件实例
*/
@Override
protected CircleView createViewInstance(ThemedReactContext reactContext) {
this.mContext = reactContext;
this.mContext.addLifecycleEventListener(this);
final CircleView circleView = new CircleView(reactContext);
circleView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
WritableMap data = Arguments.createMap();
data.putString("msg","native UI被点了");
mContext.getJSModule(RCTEventEmitter.class).receiveEvent(
circleView.getId(), // RN层原生层根据id绑定在一起
EVENT_NAME_ONCLICK, // 事件名称
data // 传递的数据
);
}
});
return circleView;
}
/**
* 设置背景色
*/
@ReactProp(name = "color")
public void setColor(CircleView view, Integer color) {
view.setColor(color);
}
/**
* 设置半径
*/
@ReactProp(name = "radius")
public void setRadius(CircleView view, Integer radius) {
view.setRadius(radius);
}
/**
* 自定义事件
*/
@Nullable
@Override
public Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(EVENT_NAME_ONCLICK, MapBuilder.of("registrationName",EVENT_NAME_ONCLICK));
}
/**
* 接收交互通知
* */
@Nullable
@Override
public Map<String, Integer> getCommandsMap() {
return MapBuilder.of(HANDLE_METHOD_NAME,HANDLE_METHOD_ID);
}
/**
* 处理通知
* */
@Override
public void receiveCommand(CircleView root, int commandId, @Nullable ReadableArray args) {
switch (commandId){
case HANDLE_METHOD_ID:
Log.d("ACCEPT========","come here");
Toast.makeText(mContext,"RN层任务通知",Toast.LENGTH_LONG).show();
if (args!=null){
// String message=args.getString(0); //获取
// Toast.makeText(mContext,"RN层任务通知",Toast.LENGTH_LONG).show();
}
break;
default:
break;
}
}
@Override
public void onHostResume() {
}
@Override
public void onHostPause() {
}
@Override
public void onHostDestroy() {
}
}
RN与原生UI的交互逻辑在ViewManager处理,相关方法的使用,注释已说明.
3.创建本地模块包.
package com.firstapp.widget.manager;
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;
/**
* Description:
* Created by song on /7/23.
* email:bjay0613@
*/
public class CirclePackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList(
new CircleViewManager()
);
}
}
4.在Application添加自定义的模块:
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 CustomToastPackage(),
mImagePickerPackage,
new NativePagePackage(),
new CirclePackage(),
new UpdateAndroidPackage()
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@Nullable
@Override
protected String getJSBundleFile() {
File file = new File(getExternalCacheDir(), FILE_NAME);
if (file != null && file.length() > 0) {
return file.getAbsolutePath();
}
return super.getJSBundleFile();
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
5.js中通过requireNativeComponent调用原生UI组件.(Circle.js)
import React, { Component } from 'react';
import {
View,
requireNativeComponent,
} from 'react-native';
import {PropTypes} from 'prop-types'
var iFace={
name:'Circle',
propTypes:{
color:PropTypes.number,
radius:PropTypes.number,
...View.propTypes // 包含默认的View的属性
},
nativeOnly:{
onclick:true
}
}
module.exports=requireNativeComponent('MCircle', iFace);
6.在js中对其相关处理做进一步封装.
import React, { Component } from 'react';
import {
View,
UIManager,
findNodeHandle
} from 'react-native';
import {PropTypes} from 'prop-types'
import MCircle from '../native_modules/Circle'
var RCT_CIRCLE_REF='MCircle'
export default class Circle extends Component {
static propTypes = {
radius: PropTypes.number,
color: PropTypes.number, // 这里传过来的是string
...View.propTypes // 包含默认的View的属性
}
onClick(event) {
if(this.props.onClick) {
if(!this.props.onClick){
return;
}
// 使用event.nativeEvent.msg获取原生层传递的数据
this.props.onClick(event.nativeEvent.msg);
}
}
handleTask() {
//向native层发送命令
// noinspection JSDeprecatedSymbols
UIManager.dispatchViewManagerCommand(
findNodeHandle(this.refs[RCT_CIRCLE_REF]),
mands.handleTask,
null)
}
render() {
const { style, radius, color } = this.props;
return (
<View>
<MCircle
ref={RCT_CIRCLE_REF}
style={style}
radius={radius}
color={color}
onClick={(event)=> this.onClick(event)}
/>
</View>
);
}
}
7.直接使用:
<View style={styles.rowContainer}>
<Circle ref={(circle)=>{this.circle = circle}}
style={{width: 100, height: 100}}
color={processColor("#f45675")}
radius={50}
onClick={(msg)=>Alert.alert("js press",msg)}/>
</View>
最后奉上源码:/RightOfHand/FirstApp.git