react-native调用Android原生UI组件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_23575795/article/details/83472515

当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 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(){

}

}

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.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<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 2018/7/23.

* email:[email protected]

*/

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]),

UIManager.MCircle.Commands.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>

最后奉上源码:https://github.com/RightOfHand/FirstApp.git

猜你喜欢

转载自blog.csdn.net/qq_23575795/article/details/83472515