参考:http://blog.csdn.net/pz789as/article/details/52448048
自定义view: 自己写原生的view显示在RN界面上。
这次主要是项目需要绘制一张大图,里面有很多节点和线,如果使用单纯RN提供的view去做,需要的内存不够(量级在K以上),所以需要想办法在一个view中画所有的点和线。
自己在想的过程中,也去找了一些相关的RN插件,一个是react-native-svg,很好的插件,由于我需要动态更改节点和线的位置,这个插件不能很好的展示,所以放弃了。另外找到一个办法,这个其实就是svg提示,因为svg就是封装了RN自带的ART组件,该组件是RN提供,可以绘制各种图形,虽然可以变换位置等,也有很大弊端,不能使用setNativeProps函数,这个比较要命。因为频繁更新,不用这个函数很容易卡死。
最后辗转了各个网页,实在没办法打算自己写一个。
还好RN留下的借口很牛逼,可以嵌入各种自己写的原生代码。跟着教程写的,具体操作可以看下面网址:
这里简单说下重点,因为当时自己看的时候也是没看懂(主要是这个api直接拿RNMap去举例,并没有其他的)
1,在xcode里面创建2个类,分别RCT***.h .m 和 RCT***Manager.h .m,这貌似是RN规定的固定写法(自己也不知道,反正照着葫芦画瓢就好了)?
我这里多写了一个,自己懵懂,是按照一个插件去写的,其实实现drawRect可以写在RCTDrawView里面,我多写了一步;
2,Manager类需要继承 RCTViewManager
// RCTDrawViewManager.h
#import "RCTViewManager.h"
@interface RCTDrawViewManager : RCTViewManager
@end
另一个就继承UIView就可以了。关键点是Manager这个,它相当于是原生和RN的桥梁,如果做过RN的原生模块就知道,和模块类似。
@implementation RCTDrawViewManager
RCT_EXPORT_MODULE();
@synthesize bridge = _bridge;
- (UIView *)view
{
return [[RCTDrawView alloc] init];
}
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor);
RCT_EXPORT_VIEW_PROPERTY(drawData, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(transPos, CGPoint);
RCT_EXPORT_VIEW_PROPERTY(scaleValue, CGPoint);
//RCT_CUSTOM_VIEW_PROPERTY(transPos, TransPos, RCTDrawView)
//{
// [view setTransPos:json ? [RCTConvert TransPos:json] : defaultView.transPos];
//}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
@end
RCT_EXPORT_MODULE 导出模块,可以加个参数,字符串,标识这个模块的名称
RCT_EXPORT_VIEW_PROPERTY 导出属性,可以在js那边设置,如: <DrawView transPos={{x:0,y:0}}/>,我这里是要传一个偏移位置,所以通过JSON的格式传递,很多复杂的数据都可以这样传递,我的drawData就是,传到这边之后可以通过RCTConvert去转换成NSDictionary,当然RN也给我们封装了些常用的,如CGPoint,CGRect等等,可以去RCTConvert中查看,很丰富。
methodQueue 这个是指定线程,因为RN规定渲染需要在主线程中,所以添加这一句话,标识运行在哪个线程中,有很多第三方SDK可能需要这个设定,比如语音识别。
3,RCTDrawVIew里面主要说一点,就是在Manager里面定义的属性,需要在这个里面实现,或者说接收,比如我自己定义的
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
if ([_backgroundColor isEqual:backgroundColor]) {
return;
}
_backgroundColor = backgroundColor;
[self layoutSubviews];
}
-(void)setTransPos:(CGPoint)transPos
{
self.drawView.transPos = transPos;
[self layoutSubviews];
}
-(void)setScaleValue:(CGPoint)scaleValue
{
self.drawView.scaleValue = scaleValue;
[self layoutSubviews];
}
-(void)setDrawData:(NSDictionary *)drawData
{
self.drawView.drawData = drawData;
[self layoutSubviews];
}
名称都是一一对应的,前面加一个set就可以了。每次在js端设置了属性变更,就会触发这里的set函数,然后就可以做你想做的任何事情了。
我是要更新drawRect,所以要手动的设置 [self.drawViewsetNeedsDisplay]; ,这样一来,就可以更新drawRect里面的内容啦
4,下面看看解析drawData,主要是RCTConvert去转换。
NSArray * orderKey = [RCTConvert NSArray:_drawData[@"order"]];
for (NSString *key in orderKey) {
NSArray* array = [RCTConvert NSArray:_drawData[key]];
if ([key containsString:@"lines"]){
for (int i=0; i<array.count; i++) {
color = [RCTConvert UIColor:array[i][@"color"]];
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetLineWidth(context, [RCTConvert CGFloat:array[i][@"stroke"]]);
CGPoint aPoints[2];//坐标点
aPoints[0] =CGPointMake([RCTConvert CGFloat:array[i][@"x1"]], [RCTConvert CGFloat:array[i][@"y1"]]);//坐标1
aPoints[1] =CGPointMake([RCTConvert CGFloat:array[i][@"x2"]], [RCTConvert CGFloat:array[i][@"y2"]]);//坐标2
CGContextAddLines(context, aPoints, 2);//添加线
CGContextDrawPath(context, kCGPathStroke); //根据坐标绘制路径
}
}
}
<span style="font-family: Arial, Helvetica, sans-serif;">}</span>