当react-native的UI组件不能满足需求时,可以考虑在原生自定UI组件,让RN调用.使用原生UI所考虑的问题:
一.原生UI被调用;
二.修改原生UI属性值;
三.捕捉原生UI的响应;
四.RN向原生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 2018/7/23.
* email:[email protected]
*/
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(){
}
}
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.facebook.react.common.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 2018/7/23.
* email:[email protected]
*/
public class CircleViewManager extends SimpleViewManager
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
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处理,相关方法的使用,注释已说明.
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 2018/7/23.
* email:[email protected]
*/
public class CirclePackage implements ReactPackage {
@Override
public List
return Collections.emptyList();
}
@Override
public List
return Arrays.
new CircleViewManager()
);
}
}
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List
return Arrays.
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);
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]),
UIManager.MCircle.Commands.handleTask,
null)
}
render() {
const { style, radius, color } = this.props;
return (
ref={RCT_CIRCLE_REF} style={style} radius={radius} color={color} onClick={(event)=> this.onClick(event)} /> ); } } style={{width: 100, height: 100}} color={processColor("#f45675")} radius={50} onClick={(msg)=>Alert.alert("js press",msg)}/> 最后奉上源码:https://github.com/RightOfHand/FirstApp.git 7.直接使用: