1、创建 ViewManager 的子类
2、实现方法 createViewInstance
@Override
protected DrawCanvasView createViewInstance(ThemedReactContext reactContext) {
this.mContext = reactContext;
return new DrawCanvasView(reactContext.getApplicationContext(), reactContext);
}
3、通过 @ReactProp 注解导出属性的设置方法
@ReactProp注解必须包含一个字符串类型的参数name。这个参数指定了对应属性在JavaScript 端的名字。
@ReactProp(name = PROP_DRAW)
public void setCanvasType(final DrawCanvasView drawCanvasView, boolean type) {
System.out.println(TAG + " " + type);
if (type) {
//代表老师,可以绘制画板
drawCanvasView.setCanvasType(CanvasType.CAN_DRAW);
} else {
//代表学生,可以看画板,不能绘制
drawCanvasView.setCanvasType(CanvasType.CAN_SHOW);
}
}
4、注册 ViewManager
//DrawCanvasPackage.java
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
return Arrays.asList(
new DrawCanvasManager()
);
}
5、实现对应的 JavaScript 模块
//DrawCanvasView.js
importReact, {Component,PropTypes}from'react';
import{requireNativeComponent,View}from'react-native';
export default classDrawCanvasViewextendsComponent{
constructor(props) {
super(props);
};
_onDraw=(event)=> {
if(this.props.onDraw) {
this.props.onDraw(event.nativeEvent);
}
}
_onDrawUp=(event)=>{
if(this.props.onDrawUp){
this.props.onDrawUp(event.nativeEvent);
}
}
_onMenuClick=(event)=>{
if(this.props.onMenuClick){
this.props.onMenuClick(event.nativeEvent);
}
}
setNativeProps(nativeProps) {
this._root.setNativeProps(nativeProps);
}
loadMaterial= (material) => {
this.setNativeProps({material: material});
}
sendCommand= (holder) => {
this.setNativeProps({send_command: holder});
}
_assignRoot= (component) => {
this._root= component;
}
render() {
constnativeProps= Object.assign({},this.props);
Object.assign(nativeProps, {
style:nativeProps.style,
loadMaterial:this.loadMaterial,
sendCommand:this.sendCommand,
onDraw:this._onDraw,
onDrawUp:this._onDrawUp,
onMenuClick:this._onMenuClick,
})
return(
<RCTDrawCanvasView
ref={this._assignRoot}
{...nativeProps}
/>
)
}
}
DrawCanvasView.propTypes={
...View.propTypes,
material:PropTypes.func,
send_command:PropTypes.func,
onDraw:PropTypes.func,
onDrawUp:PropTypes.func,
can_draw:PropTypes.bool,
onMenuClick:PropTypes.func,
}
constRCTDrawCanvasView=requireNativeComponent("DrawCanvasView",DrawCanvasView,null)
6、自定义事件注册
对于用户的操作,例如绘制画板,缩放,拖拽,JS端需要响应用户的操作,所以需要原生视图向JS端发送事件,传递数据。
·列举注册事件
//PaintView.java
public enumEvents {
EVENT_ON_DRAW("onDraw"),
EVENT_ON_DRAW_UP("onDrawUp"),
EVENT_MENU_CLICK("onMenuClick");
private finalStringmName;
Events(finalString name) {
mName= name;
}
@Override
publicStringtoString() {
returnmName;
}
}
·导出自定义事件
//DrawCanvasManager.java
@Override
@Nullable
publicMapgetExportedCustomDirectEventTypeConstants() {
MapBuilder.Builder builder = MapBuilder.builder();
for(Events event : Events.values()) {
builder.put(event.toString(),MapBuilder.of("registrationName",event.toString()));
}
returnbuilder.build();
}
·发送事件
//DrawCanvasView.java
@Override
public voidonClick(View v) {
WritableMap event= Arguments.createMap();
switch(v.getId()) {
caseR.id.ll_undo:
mPaintView.undo();
event.putInt("command",Command.UNDO);
break;
caseR.id.ll_redo:
mPaintView.redo();
event.putInt("command",Command.REDO);
break;
caseR.id.ll_reset:
mPaintView.clear();
event.putInt("command",Command.CLEAR);
break;
caseR.id.ll_save:
mPaintView.clear();
event.putInt("command",Command.SAVE);
break;
default:
Log.i("ID---view",Integer.toString(v.getId()));
break;
}
// System.out.println(TAG+"1 "+getId());
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
getId(),PaintView.Events.EVENT_MENU_CLICK.toString(),event);
}
7、原生端接收 JS 端传递的数据解析
使用ReadableMap接收数据,如果接收的是数组则使用ReadableArray
/**
*画板接收到命令
*
*@paramdrawCanvasView
*@paramholder
*/
@ReactProp(name=PROP_COMMAND)
public voidsendCommand(finalDrawCanvasView drawCanvasView,ReadableMap holder) {
System.out.println(TAG+" "+holder);
intcommand = holder.getInt("command");
switch(command) {
caseCommand.DRAW: {
ReadableArray path=holder.getArray("path");
floatsize=(float) holder.getDouble("paintSize");
intcolor=holder.getInt("paintColor");
drawCanvasView.sendDrawCommand(command,path,size,color);
}
break;
/* case Command.DRAG:{
float x=(float)holder.getDouble("currentDistanceX");
float y=(float)holder.getDouble("currentDistanceY");
drawCanvasView.sendCommand(x,y);
}
break;*/
caseCommand.GESTURE:{
ReadableArray data=holder.getArray("data");
drawCanvasView.sendCommand(data);
}
default:
//数据只有command
drawCanvasView.sendCommand(command);
break;
}
}
8、原生组件使用
onDraw , onDrawUp , onMenuClick皆是用于响应用户操作,原生向 JS端 发送事件
<DrawCanvasView
ref={(ref)=>{this._drawCanvas=ref}}
onDraw={(e)=>this.onDraw(e)}
onDrawUp={(e)=>this.onDrawUp(e)}
can_draw={true}
onMenuClick={(e)=>this._onMenuClick(e)}
style={{width:width,height:536*size}}/>
主要代码展示
//DrawCanvasManager.java
public classDrawCanvasManagerextendsSimpleViewManager {
private staticString TAG = DrawCanvasManager.class.getSimpleName();
public static finalString PROP_MATERIAL ="material";
public static finalString PROP_DRAW ="can_draw";
public static finalString PROP_COMMAND ="send_command";
privateContext mContext;
@Override
publicString getName() {
return"DrawCanvasView";
}
@Override
protectedDrawCanvasView createViewInstance(ThemedReactContext reactContext) {
this.mContext = reactContext;
return newDrawCanvasView(reactContext.getApplicationContext(),reactContext);
}
@Override
@Nullable
publicMap getExportedCustomDirectEventTypeConstants() {
MapBuilder.Builder builder = MapBuilder.builder();
for(Events event : Events.values()) {
builder.put(event.toString(),MapBuilder.of("registrationName",event.toString()));
}
returnbuilder.build();
}
/**
* name名称不能包含大写
*
*@paramdrawCanvasView
*@parammaterial
*@throwsException
*/
@ReactProp(name = PROP_MATERIAL)
public voidloadMaterial(finalDrawCanvasView drawCanvasView,ReadableMap material)throwsException {
//content://路径
/* Uri url=Uri.parse(material.getString("uri"));
String _uri=getRealFilePath(mContext,url);
FileInputStream fis=new FileInputStream(_uri);*/
//真实路径
// Bitmap bitmap=BitmapFactory.decodeFile(uri);
//图片资源
intname =0;
String _name = material.getString("uri");
if(_name.equals("image1")) {
// name=R.drawable.image1;
name = R.drawable.ic_iamge1;
}else if(_name.equals("image2")) {
name = R.drawable.image2;
//name=R.drawable.ic_image2;
}else if(_name.equals("image3")) {
name = R.drawable.image3;
}
/* InputStream fis=mContext.getResources().openRawResource(name);
Bitmap bitmap = BitmapFactory.decodeStream(fis);
if(bitmap==null){
return;
}
System.out.println("DrawCanvasManager==" + material.getString("uri")+" "+bitmap);
//最好是矢量图,位图缩放后会变得模糊
// Bitmap newBitMpa=big(bitmap);
drawCanvasView.drawImage(bitmap,(float) material.getDouble("left"),(float) material.getDouble("top"));*/
Drawable drawable = ContextCompat.getDrawable(mContext,name);
drawCanvasView.addSticker(newDrawableSticker(drawable));
}
/**
*设置Canvas画布的类型
*
*@paramdrawCanvasView
*@paramtype
*/
@ReactProp(name = PROP_DRAW)
public voidsetCanvasType(finalDrawCanvasView drawCanvasView, booleantype) {
System.out.println(TAG +" "+ type);
if(type) {
//代表老师,可以绘制画板
drawCanvasView.setCanvasType(CanvasType.CAN_DRAW);
}else{
//代表学生,可以看画板,不能绘制
drawCanvasView.setCanvasType(CanvasType.CAN_SHOW);
}
}
/**
*画板接收到命令
*
*@paramdrawCanvasView
*@paramholder
*/
@ReactProp(name = PROP_COMMAND)
public voidsendCommand(finalDrawCanvasView drawCanvasView,ReadableMap holder) {
System.out.println(TAG+" "+holder);
intcommand = holder.getInt("command");
switch(command) {
caseCommand.DRAW: {
ReadableArray path=holder.getArray("path");
floatsize=(float) holder.getDouble("paintSize");
intcolor=holder.getInt("paintColor");
drawCanvasView.sendDrawCommand(command,path,size,color);
}
break;
/* case Command.DRAG:{
float x=(float)holder.getDouble("currentDistanceX");
float y=(float)holder.getDouble("currentDistanceY");
drawCanvasView.sendCommand(x,y);
}
break;*/
caseCommand.GESTURE:{
ReadableArray data=holder.getArray("data");
drawCanvasView.sendCommand(data);
}
default:
//数据只有command
drawCanvasView.sendCommand(command);
break;
}
}
/**
* Try to return the absolute file path from the given Uri
*
*@paramcontext
*@paramuri
*@returnthe file path or null
*/
public staticString getRealFilePath(finalContext context, finalUri uri) {
if(null== uri)return null;
finalString scheme = uri.getScheme();
String data =null;
if(scheme ==null) {
data = uri.getPath();
}else if(ContentResolver.SCHEME_FILE.equals(scheme)) {
data = uri.getPath();
}else if(ContentResolver.SCHEME_CONTENT.equals(scheme)) {
Cursor cursor = context.getContentResolver().query(uri, newString[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
if(null!= cursor) {
if(cursor.moveToFirst()) {
intindex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
if(index > -1) {
data = cursor.getString(index);
}
}
cursor.close();
}
}
returndata;
}
private staticBitmap big(Bitmap bitmap) {
Matrix matrix =newMatrix();
matrix.postScale(2.5f,2.5f);//长和宽放大缩小的比例
Bitmap resizeBmp = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix, true);
returnresizeBmp;
}
}
//DrawCanvasView.java
public classDrawCanvasViewextendsRelativeLayoutimplementsView.OnClickListener,OnSeekBarChangeListener,PaintView.OnDrawListener,PaintView.OnStickerOperationListener{
privatePaintViewmPaintView;
privateVerticalSeekBarmVerticalSeekBar;
private static finalStringTAG= DrawCanvasView.class.getSimpleName();
privateContextmContext;
privateReactContextreactContext;
ViewbtnUndo,btnRedo;
publicDrawCanvasView(Context context,ReactContext reactContext) {
super(context);
this.mContext= context;
this.reactContext=reactContext;
LayoutInflater.from(context).inflate(R.layout.activity_draw, this);
initView(context);
}
public voidinitView(Context context) {
//初始化颜色板
// initColorPickerDialog();
//初始化自定义的ToolBar
initToolbar();
mPaintView= (PaintView) findViewById(R.id.draw_view);
mVerticalSeekBar= (VerticalSeekBar) findViewById(R.id.seekBar);
mVerticalSeekBar.setOnSeekBarChangeListener(this);
mPaintView.setStrokeWidth(mVerticalSeekBar.getProgress());
mPaintView.setBgColor(Color.WHITE);
mPaintView.setOnDrawListener(this);
mPaintView.setOnStickerOperationListener(this);
mPaintView.setConstrained(true);
mPaintView.myContext=reactContext;
}
/**
*初始化自定义toolbar
*/
private voidinitToolbar() {
btnUndo=findViewById(R.id.ll_undo);
btnUndo.setOnClickListener(this);
btnUndo.setEnabled(false);
btnRedo=findViewById(R.id.ll_redo);
btnRedo.setOnClickListener(this);
btnRedo.setEnabled(false);
findViewById(R.id.ll_reset).setOnClickListener(this);
findViewById(R.id.ll_save).setOnClickListener(this);
}
@Override
public voidonClick(View v) {
WritableMap event= Arguments.createMap();
switch(v.getId()) {
caseR.id.ll_undo:
mPaintView.undo();
event.putInt("command",Command.UNDO);
break;
caseR.id.ll_redo:
mPaintView.redo();
event.putInt("command",Command.REDO);
break;
caseR.id.ll_reset:
mPaintView.clear();
event.putInt("command",Command.CLEAR);
break;
caseR.id.ll_save:
mPaintView.clear();
event.putInt("command",Command.SAVE);
break;
default:
Log.i("ID---view",Integer.toString(v.getId()));
break;
}
// System.out.println(TAG+"1 "+getId());
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
getId(),PaintView.Events.EVENT_MENU_CLICK.toString(),event);
}
@Override
public voidonProgressChanged(SeekBar seekBar, intprogress, booleanfromUser) {
mPaintView.setStrokeWidth(progress);
}
@Override
public voidonStartTrackingTouch(SeekBar seekBar) {
}
@Override
public voidonStopTrackingTouch(SeekBar seekBar) {
}
public voiddrawImage(Bitmap bitmap, floatleft, floattop) {
mPaintView.drawImage(bitmap,left,top);
}
@Override
public voidafterPaintInit(intviewWidth, intviewHeight) {
}
@Override
public voidafterEachPaint(ArrayList drawShapes) {
setUndoEnable(drawShapes);
}
@Override
public voidafterRedoEachPaint(ArrayList drawShapes) {
setRedoEnable(drawShapes);
}
private voidsetUndoEnable(ArrayList drawShapes) {
if(drawShapes.size() ==0) {
btnUndo.setEnabled(false);
}else{
btnUndo.setEnabled(true);
}
}
private voidsetRedoEnable(ArrayList drawShapes) {
if(drawShapes.size() ==0) {
btnRedo.setEnabled(false);
}else{
btnRedo.setEnabled(true);
}
}
public voidaddSticker(@NonNullSticker sticker){
addSticker(sticker,Sticker.Position.CENTER);
}
public voidaddSticker(@NonNullfinalSticker sticker,final@Sticker.Positionintposition){
if(ViewCompat.isLaidOut(this)){
mPaintView.addStickerImmediately(sticker,position);
}else{
post(newRunnable() {
@Overridepublic voidrun() {
mPaintView.addStickerImmediately(sticker,position);
}
});
}
}
public voidsetCanvasType(@NonNullCanvasType type){
mPaintView.viewId=getId();
System.out.println(TAG+"2 "+getId());
mPaintView.setCanvasType(type);
}
public voidsendDrawCommand(intcommand,ReadableArray path, floatpaintSize, intpaintColor){
mPaintView.sendDrawCommand(command,path,paintSize,paintColor);
}
public voidsendCommand(intcommand){
switch(command){
caseCommand.UNDO:{
mPaintView.undo();
}
break;
caseCommand.CLEAR:{
mPaintView.clear();
}
break;
caseCommand.REDO:{
mPaintView.redo();
}
break;
caseCommand.SAVE:{
}
}
}
/* public void sendCommand(float x,float y){
mPaintView.sendCommand(x,y);
}*/
public voidsendCommand(ReadableArray data){
mPaintView.sendCommand(data);
}
@Override
public voidonStickerAdded(@NonNullSticker sticker) {
Log.i(TAG,"onStickerAdded");
}
@Override
public voidonStickerClicked(@NonNullSticker sticker) {
Log.i(TAG,"onStickerClicked");
}
@Override
public voidonStickerDeleted(@NonNullSticker sticker) {
}
@Override
public voidonStickerDragFinished(@NonNullSticker sticker) {
}
@Override
public voidonStickerZoomFinished(@NonNullSticker sticker) {
}
@Override
public voidonStickerFlipped(@NonNullSticker sticker) {
}
@Override
public voidonStickerDoubleTapped(@NonNullSticker sticker) {
}
@Overridepublic booleanonInterceptTouchEvent(MotionEvent ev) {
mPaintView.onInterceptTouchEvent(ev);
return super.onInterceptTouchEvent(ev);
}
}
海说接受react各种技术咨询及开发业务
-END-
网友评论