SVG对骑手端weex绘图功能扩展实践

Posted 点我达技术团队

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SVG对骑手端weex绘图功能扩展实践相关的知识,希望对你有一定的参考价值。

前言

公司采用weex对骑手工程改造已经有3个多月了,随着骑手工程中weex页面比例不断增大,对weex来实现复杂UI的需求也越来越强烈,插件市场的插件长期没人维护,开发者苦不堪言,我们对此进行了探索,出于对androidios,web兼容的考虑,我们选择了svg技术对weex进行插件扩展的研究,希望能帮助到正在使用weex开发的小伙伴们少走些弯路。

1.SVG简介

   1.1 什么是SVG?

  • SVG指可伸缩矢量图形(Scalable Vector Graphics)

  • SVG用来定义用于网络的基于矢量的图形;

  • SVG使用xml格式定义图形;

  • SVG图像在放大或改变尺寸的情况下其图形质量不会有所损失;

  • SVG是万维网联盟的标准;

  • SVG与诸如DOM和XSL之类的W3C标准是一个整体(于2003年1月14日成为W3C推荐标准)。


   1.2 SVG工作流?

SVG对骑手端weex绘图功能扩展实践


  1.3 为什么选择SVG?

  • SVG是基于XML与html语义一样,具有很好的交互性,图像文件可读,易于修改和编辑。

  • 目前主流的平台及android,iOS,web都有比较好的支持。

   

   1.4 SVG优势

  • 可通过文本编辑器来创建和修改

  • 图像中的文本是可选的,同时也是可搜索的(很适合制作地图)

  • SVG可在任何的分辨率下被高质量的打印

  • 可在图片质量不下降的情况下被放大

  • SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。

  • 支持事件绑定

  • SVG 可以与 Java 技术一起运行

  • SVG 是开放的标准

  • SVG 文件是纯粹的 XML

   1.5 SVG实例

 
   
   
 
  1. <?xml version="1.0" standalone="no"?>

  2. <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"

  3. "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

  4. <svg width="100%" height="100%" version="1.1"

  5. xmlns="http://www.w3.org/2000/svg">

  6. </svg>

  7. <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>

  8. </svg>

   

   1.6 SVG预定义的形状元素

  • 矩形 <rect>

  • 圆形 <circle>

  • 椭圆 <ellipse>

  • 线 <line>

  • 折线 <polyline>

  • 多边形 <polygon>

  • 路径 <path>

2. Weex 插件扩展(有相关经验的小伙伴可忽略)

SVG对骑手端weex绘图功能扩展实践

2.1 weex-iOS插件扩展方式介绍

iOS组件 Component扩展步骤

iOS端 *1.创建自定义的组件继承WXComponent类 *2.重写- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance方法 *3.现实自定义的UI样式 *4.支持js方法在特殊的状态调用重写addEvent和removeEvent方法,在需要的位置调用fireEvent方法执行对应的js方法 *5.支持js调模块扩展出来的方法,编写扩展方法WXEXPORTMETHOD(@selector(method))扩展 *6.使用WXSDKEngine的+registerComponent:withClass:去注册 js端 1.直接在需要该组件的template中使用 2.如果组件需要传递参数,则可以通过:key=value的形式传递,方法@methodName=JSmethod,实现js方法 3.调用扩展方法:this.$refs.refName.methodName

iOS模块 Module扩展步骤

iOS端 *1.创建自定义的模块实现 协议 *2.实现自定义的功能并callback回调给js *3.使用WX EXPORTMETHOD或WX EXPORTMETHOD_SYNC来抛出native方法给js *4.使用WXSDKEngine的+registerModule:withClass:去注册 js端 1.直接在需要该组件的script中使用weex.requireModule()获得已注册的模块 2.在需要的位置调用注册的方法

2.2 weex-android插件扩展方式介绍

android组件 Component扩展步骤

android端 *1.创建自定义的组件继承WXComponent/WXVContainer类 *2.使用initComponentHostView(context)初始化,initView()方法已过时 *3.现实自定义的UI样式, 通过添加注解@WXComponentProp设置属性 *4.使用instance.fireEvent()方法执行对应的js方法 *5.支持js调模块扩展出来的方法,编写扩展方法@JSMethod(uiThread = false或true)扩展 *6.使用WXSDKEngine的WXSDKEngine.registerComponent()去注册 js端 1.直接在需要该组件的template中使用 2.如果组件需要传递参数,则可以通过:key=value的形式传递,方法@methodName=JSmethod,实现js方法 3.调用扩展方法:this.$refs.refName.methodName

android模块 Module扩展步骤

android端 *1.创建自定义的模块继承WXModule *2.实现自定义的功能并callback回调给js *3.使用@JSMethod(uiThread = false或true)将自定义的方法抛给js *4.使用WXSDKEngine的WXSDKEngine.registerModule()去注册 js端 1.直接在需要该组件的script中使用weex.requireModule()获得已注册的模块 2.在需要的位置调用注册的方法

2.3 weex-web插件扩展方式介绍

web组件 Component扩展步骤

js端 1.使用npm install加载weex-vue-render组件 2.使用Weex.registerComponent('name', component); 注册组件 3.在webpack.config中使用weex.install(components)加载所有组件 4.调用扩展方法:

web组件 Module扩展步骤

js端

  1. 使用npm install加载weex-vue-render组件

  2. 使用Weex.registerModule('name', module)

  3. 在webpack.config中使用weex.install(modules)加载所有组件 4.调用扩展方法:const moduleName = weex.requireModule('ModuleName'); 调用模块方法moduleName.xx()

3.Weex 交互(有相关经验的小伙伴可忽略)

3.1 Weex-web和native交互(iOS使用WKWebView,android使用WebView)

Weex-web端

1.Weex-web调用native提供的方法: iOS:webkit.messageHandlers.weexCallHandler.postMessage(data) android:window.dianwoda.weexCallHandler(data); 2.解决方案:使用callHandler的调用方式来实现 参数: a. name:调用native的方法名,即约定的具体需要调用native的什么方法,例:setHeaderTitle(设置header的title) b. params:传给native端的参数,例:{'title': '这是商品详情页的标题'} c. onSuccess:调用native方法成功后的回调方法名 d. onFail:调用native的方法名,即约定的具体需要调用native的什么方法,例:setHeaderTitle(设置header的title) 3.问题:由webpack打包生成的Weex-web的vuejs文件的methods方法不在window下native无法调用到, 解决方案:将方法绑到window下面

iOS端

1.iOS调用Weex-web的方法回传数据:[webView evaluatejavascript:jsStr completionHandler:^(id _Nullable d, NSError * _Nullable error) {}];

android端

1.android调用Weex-web的方法回传数据:通过getSettings()获得WebSettings,然后用setJavaScriptEnabled()调用Js

 3.2 Weex和iOS交互

1.Weex调用iOS的方法

方式1:通过iOS注册的Module方式来抛出方法供weex调用

2.iOS调用weex的方法

方式1:拿到weex页面的instanceId通过fireEvent方法调用weex方法 如:[[WXSDKManager bridgeMgr] fireEvent:weexInstance.instanceId ref:WXSDKROOT_REF type:type params:params domChanges:nil]; 方式2:在组件中使用fireEvent方法来调用weex方法 方式3:使用fireGlobalEvent来通知调用weex方法

注:fireEvent方式是通过JSContext实现,fireGlobalEvent是通过通知实现

3.3 Weex和android交互 

1.Weex调用android的方法

方式1:通过android注册的Module方式来抛出方法供weex调用

2.android调用weex的方法

方式1:拿到weex页面的instance通过fireEvent(getRef(), numClick, data, null);方法来调用weex方法 方式2:使用fireGlobalEvent来广播调用weex方法

注:fireEvent方式是通过webView调用js实现,fireGlobalEvent是通过广播实现

4.Weex SVG实践

4.1 Weex-web SVG扩展

SVG可在Weex-web上直接使用:

例如:使用 <path>绘制一段弧形

 
   
   
 
  1. <svg>

  2.    <path d="M 0,304 C 0,304 375,270 750,0" stroke-width="4"  stroke="#3A3A41" fill="#42424F" />

  3. </svg>

代码解释: path> 标签用来定义路径。 下面的命令可用于路径数据: M = moveto L = lineto H = horizontal lineto V = vertical lineto C = curveto S = smooth curveto Q = quadratic Belzier curve T = smooth quadratic Belzier curveto A = elliptical Arc Z = closepath 注释:以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。

SVG对骑手端weex绘图功能扩展实践

4.2 Weex-iOS SVG扩展

思路:根据svg api规范在iOS端通过 Core Graphics库来实现一套iOS-svg标准的组件库,并通过weex Component的方式把这个组件库暴露给weex使用。

  • 4.2.1.使用Core Graphics来定义符合svg api规范的各种view,如线,圆形,矩形等等。

Core Graphics的使用介绍 这是一个绘图专用的API族,它经常被称为QuartZ或QuartZ 2D。Core Graphics是iOS上所有绘图功能的基石,包括UIKit。

基本概念:

1.绘图需要 CGContextRef

CGContextRef即图形上下文。可以这么理解,我们绘图是需要一个载体或者说输出目标,它用来显示绘图信息,并且决定绘制的东西输出到哪个地方。

2.怎么拿到context?

第一种方法是利用cocoa为你生成的图形上下文。 第二种方法就是创建一个图片类型的上下文

Core Graphics的使用步骤:

1.先在drawRect方法中获得上下文context; 2.绘制图形(线,图形,图片等); 3.设置一些修饰属性; 4.渲染到上下文,完成绘图。

代码:

 
   
   
 
  1. - (void)drawRect:(CGRect)rect

  2. {

  3.    // 1.获取上下文

  4.    CGContextRef ctx = UIGraphicsGetCurrentContext();

  5.    // --------------------------实心圆

  6.    // 2.画图

  7.    CGContextAddEllipseInRect(ctx, CGRectMake(10, 10, 50, 50));

  8.    [[UIColor greenColor] set];

  9.    // 3.渲染

  10.    CGContextFillPath(ctx);

  11. }

  • 4.2.2.将使用Core Graphics来定义符合svg api规范的各种view通过Component扩展给weex。

例如:给weex扩展划线的api 1.使用Core Graphics定义一条线

 
   
   
 
  1. @implementation WXSVGLine

  2. ....

  3. - (CGPathRef)getPath:(CGContextRef)context

  4. {

  5.    [self setBoundingBox:CGContextGetClipBoundingBox(context)];

  6.    CGMutablePathRef path = CGPathCreateMutable();

  7.    CGFloat x1 = self.x1;

  8.    CGFloat y1 = self.y1;

  9.    CGFloat x2 = self.x2;

  10.    CGFloat y2 = self.y2;

  11.    CGPathMoveToPoint(path, nil, x1, y1);

  12.    CGPathAddLineToPoint(path, nil, x2, y2);

  13.    return (CGPathRef)CFAutorelease(path);

  14. }

  15. .....

  16. @end

2.通过Component把线扩展给weex使用

 
   
   
 
  1. @implementation WXSVGLineComponent

  2. .....

  3. - (WXSVGRenderable *)node

  4. {

  5.    WXSVGLine *lineView = [WXSVGLine new];

  6.    lineView.x1 = [WXConvert WXPixelType:_x1 scaleFactor:self.weexInstance.pixelScaleFactor];

  7.    lineView.y1 = [WXConvert WXPixelType:_y1 scaleFactor:self.weexInstance.pixelScaleFactor];

  8.    .....

  9.    return lineView;

  10. }

  11. - (void)updateAttributes:(NSDictionary *)attributes

  12. {

  13.    WXSVGLine *lineView = (WXSVGLine *)self.view;

  14.    if (attributes[@"x1"]) {

  15.        _x1 = attributes[@"x1"];

  16.        lineView.x1 = [WXConvert WXPixelType:_x1 scaleFactor:self.weexInstance.pixelScaleFactor];

  17.    }

  18.    .....

  19.    [super updateAttributes:attributes];

  20. }

  21. @end


4.3 Weex-android SVG扩展

思路:根据svg api规范在android端通过 graphics库来实现一套android-svg标准的组件库,并通过weex Component的方式把这个组件库暴露给weex使用。

  • 4.3.1.使用graphics来定义符合svg api规范的各种view,如线,圆形,矩形等等。

Android画图--同样有三个基本对象:Color,Paint,Canvas 它们都位于android.graphics画图包下面。 1.Canvas : 画布对象,相当于现实生活中画图用的画纸或者画布 2.Paint : 画笔对象,相当于现实生活中画图用的 笔。对画笔的一些参数设置是很重要的。 3.Color: 颜色对象,相当于现实生活中的 调料

  • 4.3.2.将使用android.graphics来定义符合svg api规范的各种view通过Component扩展给weex。

例如:给weex扩展划线的api 1.使用android.graphics定义一条线

 
   
   
 
  1. public class WXSvgLine extends WXSvgPath {

  2. .....

  3.  @Override

  4.  public void draw(Canvas canvas, Paint paint, float opacity) {

  5.    mPath = getPath(canvas, paint);

  6.    super.draw(canvas, paint, opacity);

  7.  }

  8.  @Override

  9.  protected Path getPath(Canvas canvas, Paint paint) {

  10.    Path path = new Path();

  11.    float x1 = ParserHelper.fromPercentageToFloat(mX1, mCanvasWidth, 0, mScale);

  12.    float y1 = ParserHelper.fromPercentageToFloat(mY1, mCanvasHeight, 0, mScale);

  13.    ....

  14.    path.moveTo(x1, y1);

  15.    path.lineTo(x2, y2);

  16.    return path;

  17.  }

  18.  public static class Creator implements ComponentCreator {

  19.    public Creator() {

  20.    }

  21.    public WXComponent createInstance(WXSDKInstance instance, WXDomObject node, WXVContainer parent) throws IllegalAccessException, InvocationTargetException, InstantiationException {

  22.      return new WXSvgLine(instance, node, parent);

  23.    }

  24.  }

  25. }

5.SVG编辑工具介绍

5.1 SVGSUS

SVGSUS功能特色:

  • 支持导入 SVG 图标包,管理方便

  • 可直接把图标拖至 AI/PS/SKETCH 等工具上使用

  • 图标搜索功能

  • 可输出不同终端用的 SVG 代码(如:Web/Android/iOS)

  • 下面我们来看看这个 svgsus 工具的使用体验。

导入图标包SVG对骑手端weex绘图功能扩展实践

使用图标,用户可以很方便的从软件把图标拖到 AI、PS、Sketch 等设计工具上直接使用。

SVG对骑手端weex绘图功能扩展实践

转换为 SVG 图标代码

svgsus 工具可以转换种代码格式,包括:Web, iOS, OS X, Android 等。使用方法也超简单: 方法1:单击你需要用的图标,然后在编辑器上 Ctrl + V 即可粘贴代码。 方法2:直接拖动图标到编辑器 方法3:这个有点帅,直接在拖动图标时,经过 svgsus 界面,再拖入编辑器里,就可以生成代码了,请看帅气的 DEMO 吧!

SVG对骑手端weex绘图功能扩展实践

从AI、Sketch 设计软件中输出 SVG 图标

首先在 AI 或 Sketch 里复制你要输出的图标,然后在 svgsus 上粘贴一下,最后,在文件夹里粘贴一下,完成!请看帅气的 DEMO 吧!


以上是关于SVG对骑手端weex绘图功能扩展实践的主要内容,如果未能解决你的问题,请参考以下文章

点我达骑手端weex探索

Weex技术在苏宁移动办公开发中的实践

Weex在苏宁移动办公开发中是如何实践的?

Android端WEEX_+_HTTPDNS_最佳实践

OTT 端性能优化建设之 Weex 实践之路

Weex开发系列:初识Weex