|美团积木Sketch插件进阶开发指南( 八 )


自定义属性面板功能的基本思想 , 是将组件从组件库拖至Sketch画板中时 , 组件的可修改属性可以显示在Sketch本身的属性面板上 。 我们引入了Objective-C原生开发以实现对Sketch界面的修改 , 为什么要使用原生开发?虽然官方提供了JS API并承诺持续维护 , 但这项工作一直处于Doing状态 , 而且官方文档更新缓慢 , 没有明确的时间节点 , 因此对于自定义Native Inspector Panel这种需要Hook API的功能 , 使用原生开发较为便捷 , 而且对于iOS开发者也更加友好 , 无需再学习前端界面开发知识 。
|美团积木Sketch插件进阶开发指南
本文插图

Sketch Inspector面板操作区优化
Xcode工程配置
通过Xcode工程构建自定义属性面板 , 最终生成一个可以供JS侧调用的Framework 。 可以参考上一篇文章介绍的方法创建Xcode工程 , 该工程在每次构建后会自动生成测试Sketch插件并放入对应的文件夹中 。 需要注意的一点是 , 这里生成的插件只是为了方便开发和调试 , 后面会介绍如何将XCode工程构建的Framework集成至JS主工程中 。
|美团积木Sketch插件进阶开发指南
本文插图

Xcode工程配置示意
积木插件的主体功能使用JS代码实现 , 但是自定义属性选择面板使用Objective-C代码实现 。 为了实现积木插件的JS侧功能模块与OC侧模块之间的通信和桥接 , 这里借助了Mocha框架来实现相关的功能 , Mocha框架也被Sketch官方所使用 , 将原生侧的方法封装为官方API后暴露给JS侧 。
|美团积木Sketch插件进阶开发指南
本文插图

Sketch与插件Framework通信原理
组件选中时 , Sketch软件会回调onSelectionChanged方法给JS侧 , JS侧借助Mocha框架可以实现对OC侧的调用 , 同时将参数以OC对象的方式传递 。 JS侧传递给OC侧的Context内容很丰富 , 包含了选中的组件、相关图层还有Sketch软件本身的信息 。 虽然Sketch没有提供API , 但是Objective-C语言本身具备KVO监听对象属性的能力 , 我们通过读取对应的属性值 , 就可以获取需要的对象数据 。
+ (instancetype)onSelectionChanged:(id)context { [self setSharedCommand:[context valueForKeyPath:@''command'']]; NSString *key = [NSString stringWithFormat:@''%@-RooSketchPluginNativeUI'', [document description]]; __block RooSketchPluginNativeUI *instance = [[Mocha sharedRuntime] valueForKey:key]; NSArray *selection = [context valueForKeyPath:@''actionContext.document.selectedLayers'']; [instance onSelectionChange:selection]; return instance; }Sketch官方没有将属性面板的修改能力暴露给插件侧 , 通过查询Sketch头文件发现通过reloadWithViewControllers:方法可以实现属性面板刷新 , 但是在实际开发过程中发现在某些版本的Sketch上会出现面板闪动的问题 , 这里借助Objective-C的Method Swizzle特性 , 直接修改reloadWithViewControllers:的运行时行为解决 。
[NSClassFromString(@''MSInspectorStackView'') swizzleMethod:@selector(reloadWithViewControllers:)withMethod:@selector(roo_reloadWithViewControllers:)error:nil];Swizzle方法会修改原始方法的行为 , 实际操作中只有在满足特定条件的情况下才应触发Swizzle后的方法 。
|美团积木Sketch插件进阶开发指南
本文插图

Swizzle方法触发条件
组件属性修改与替换原理
通过自定义面板可以修改组件的可覆盖项(即override) , 目前可以应用可覆盖项的affectedLayer有Text/Image/Symbol Instance三种 。 设计师与开发者在此前对图层的格式进行了约定 , 保证我们可以按照统一的方式读取并替换图层的属性值 。


推荐阅读