插件結構
http://developer.sketchapp.com/introduction/plugin-bundles/
sketch 插件就是腳本的集合。每個腳本定義了一個或者多個命令。這些命令可以拓展sketch的功能。sketch插件以 .sketchplugin
結尾,其實就是個文件夾,把后綴刪除后可以直接打開。
example.sketchplugin
Contents/
Sketch/
manifest.json
script.cocoascript
Resources/
XXX.png
XXX.png
manifest.json
這個json文件聲明插件的元數據.Sketch會讀取這個配置文件的信息,得到command的名字和command對應函數實現.
這文件里面最重要的配置項是Commands和Menu:
Commands
聲明一組command的信息。每個command以字典形式存在。
- script : 實現命令功能的函數所在的腳本
- handler: 函數名,該函數實現命令的功能。Sketch在調用該函數時,會傳入一個context參數,context是個字典,里面包含了很多信息,下文會講到。如果你的沒有指定handler,Sketch會默認是script里的onRun函數
- shortcut:命令的快捷鍵
- name:會顯示在Sketch的Plugin 的菜單里
- identifier:唯一標識,建議用com.xxxx.xxx格式
Menu
Sketch加載插件的時候,會根據它指定的信息,順序地在菜單欄中顯示命令名。
{
"author" : "rongyan.zry",
"commands" : [
{
"script" : "script.cocoascript",
"handler" : "setFixedMasks",
"shortcut" : "option m",
"name" : "Artboard Mask",
"identifier" : "com.rongyanzry.layermask"
},
{
"script" : "script.cocoascript",
"handler" : "onRun",
"shortcut" : "option s",
"name" : "Artboard Scale",
"identifier" : "com.rongyanzry.artboardscale"
}
],
"menu" : {
"items" : [
"com.rongyanzry.layermask",
"com.rongyanzry.artboardscale"
],
"title" : "Artboard Scale"
},
"identifier" : "com.rongyanzry.sketch.9a776995-f790-4048-870b-881639f52bcc",
"version" : "1.0",
"description" : "A plugin that helps you to scale artboards and layers",
"authorEmail" : ".....@gmail.com",
"name" : "Artboard Scale"
}
語言CocoaScript
This is a bridge that lets you write JavaScript scripts that can call native Objective-C/Cocoa.Using it, you can write the logic of your Plugin in JavaScript, but can call the actual classes and methods that implement Sketch itself when you want to make it do something.
在使用中用js調objective-c的方法時,
- 方法調用 用 ‘.’ 語法
- 參數都放在‘()’里頭
- oc中被參數分割開的函數名,用 ‘ _ ’連接.
- 返回值,js統一用var類型 ,js是弱類型
比如: MSPlugin的接口valueForKey:onLayer:
oc:
NSString * value = [command valueForKey:kAutoresizingMask onLayer:currentLayer];
cocoascript:
var value = command.valueForKey_onLayer(kAutoresizingMask, currentLayer);
Context
當我們輸入插件定制的命令時,Sketch會去尋找改命令對應的實現函數, 并傳入context變量。context 包含以下變量:
-
command:
MSPluginCommand
對象,代表當前執行的命令 -
document:
MSDocument
對象 ,當前的文檔 -
plugin:
MSPluginBundle
對象,當前的插件bundle,里面包含當前運行的腳本 -
scriptPath:
NSString
當前執行腳本的絕對路徑 - scriptURL: 當前執行腳本的絕對路徑,跟 scriptPath不同的是它是個 NSURL 對象
-
selection,一個
NSArray
對象,包含了當前選擇的所有圖層。數組中的每一個元素都是MSLayer
對象
// context的到的信息
var app = NSApplication.sharedApplication(),
selection,
plugin,
command,
doc,
page,
artboards,
selectedArtboard;
function initContext(context) {
doc = context.document,
plugin = context.plugin,
command = context.command,
page = doc.currentPage(),
artboards = page.artboards(),
selectedArtboard = page.currentArtboard(), // 當前被選擇的畫板
selection = context.selection, // 被選擇的圖層
for (var i=0; i<selection.count(); i++) {
var layer = selection[i]
log('layer ' + layer.name + ' is selected.')
}
}
command:
MSPluginCommand
對象,代表插件中單個命令,可以用來訪問當前執行的命令,也可以用來在圖層中存儲自己的擴展元數據。
valueForKey:onLayer
setValue:forKey:onLayer:
在圖層中存取的拓展數據,也可以在不同插件中共享。
valueForKey:onLayer:forPluginIdentifier:
setValue:forKey:onLayer:forPluginIdentifier:
document
showMessage:(NSString)message // 在sketch底部彈出信息,我經常用來打日志。。。哭
selection
當前選擇的document下的一組被選擇的MSLayers對象。
如果當前只選了一個圖層,可以這樣獲取:
var currentLayer = (selection.count() > 0) ? selection[0] : undefined
編譯環境
運行和debug
主要依賴打log.用Console.app過濾日志查看,過濾標簽可以是你寫的插件的名字,也可以用“sketch”過濾,但是這樣會得到所有命令的執行日志。
log("The value of count is:" + count)
或者在代碼中用視圖控件顯示,好處就是不用不用開第三方app.比如:
alert
, [doc showMessage]
,showMessage("message")
Sketch-Header
有人dump出來的Sketch的頭文件。信息量非常豐富哈哈~
https://github.com/abynim/Sketch-Headers
例子:
獲取畫板的所有layer:
以這個設計圖為例
https://github.com/bouchenoiremarc/Sketch-Constraints/blob/master/Example.sketch
var artboardEnumerator = artboards.objectEnumerator();
while (artboard = artboardEnumerator.nextObject()) {
//var layers = artboard.layers().array();
//var layers = artboard.children();
log(layers);
}
// layers返回畫布第一層的 subLayer
//var layers = artboard.layers().array();
/**
*
"<MSLayerGroup: 0x6180001d3b00> Group (741958C5-E1CE-468F-9AB2-E853C0799423)",
"<MSShapeGroup: 0x7f82e052c260> Camera (7E5D9F7A-2C5A-4223-AD83-8C5F340AC5EF)",
"<MSShapeGroup: 0x7f82e052de30> Control Center Grabber (936460F8-5773-4F47-89C2-C4BD246C63EC)",
"<MSLayerGroup: 0x6180001d3bf0> Slide to unlock (A240F642-0036-4629-A365-D0F537A744F8)",
"<MSTextLayer: 0x7f82e052df40> Date (9BE84955-A291-431D-8771-C36D51743FDD)",
"<MSTextLayer: 0x7f82e052e080> Time (FCF1C9FD-D6FD-4FFD-9B5F-B9D2635584BB)",
"<MSLayerGroup: 0x6180001d3ce0> Charge (6F95F078-56BC-4FDA-A319-DE0FF8C50E13)",
"<MSShapeGroup: 0x7f82e052e1c0> Notification Center Grabber (75CA34DC-7FA7-4D5B-96AB-922C23F74DC5)",
"<MSShapeGroup: 0x7f82e052e2d0> Wifi (38D4CE87-0826-405C-B13C-D30A6EE16437)",
"<MSLayerGroup: 0x6180001d3dd0> Signal (5B08C199-0398-45CC-9905-A8B16EFB5B71)",
"<MSTextLayer: 0x7f82e052e3e0> @constraints (7E04B443-1D85-48FB-B4C6-2334FE7A6408)"
**/
// 當前畫板的全部圖層
// var layers = artboard.children();
/**
* (
"<MSBitmapLayer: 0x7f82e0761c20> Wallpaper (83A6D488-6FE4-46A9-8CCF-8DBB12C1F845)",
"<MSLayerGroup: 0x6180001d3b00> Group (741958C5-E1CE-468F-9AB2-E853C0799423)",
"<MSRectangleShape: 0x610000193ce0> Path (D428D7A1-042A-4700-9D59-3CC601B79047)",
"<MSShapePathLayer: 0x610000364c80> Path (A98F99AE-2B01-49F9-B8AB-41B9913581D4)",
"<MSShapePathLayer: 0x610000364d40> Path (0B844654-8140-4A20-B090-3B41ACBBBF25)",
"<MSOvalShape: 0x610000364e00> Oval (0001F0C5-032D-47C7-BD66-41262D08D9AB)",
"<MSRectangleShape: 0x610000193db0> Rectangle (7930B492-435C-41EF-B802-7B36297D4A67)",
"<MSShapeGroup: 0x7f82e052c260> Camera (7E5D9F7A-2C5A-4223-AD83-8C5F340AC5EF)",
"<MSRectangleShape: 0x610000193c10> Path (C66C2797-E56B-4D69-9D25-B68614EEE93C)",
"<MSShapeGroup: 0x7f82e052de30> Control Center Grabber (936460F8-5773-4F47-89C2-C4BD246C63EC)",
"<MSTextLayer: 0x7f82e0761a20> Text (8D49531C-EE6F-44DB-BD5B-6CB1FC6BC8E5)",
"<MSShapePathLayer: 0x600000361800> Path (7B83C7E2-AA83-4DA4-81A5-F20AE9499B99)",
"<MSShapeGroup: 0x7f82e07613d0> Arrow (8A5109A2-945D-4D12-BF08-9026FE97D639)",
"<MSLayerGroup: 0x6180001d3bf0> Slide to unlock (A240F642-0036-4629-A365-D0F537A744F8)",
"<MSTextLayer: 0x7f82e052df40> Date (9BE84955-A291-431D-8771-C36D51743FDD)",
"<MSTextLayer: 0x7f82e052e080> Time (FCF1C9FD-D6FD-4FFD-9B5F-B9D2635584BB)",
"<MSShapePathLayer: 0x61800017c500> Path (D46E9CEA-1918-4070-8247-55D88D2F6A4F)",
"<MSShapePathLayer: 0x61800017c5c0> Path (23F3EAA0-5970-4746-BB42-3E49B5C346A5)",
"<MSShapeGroup: 0x7f82e075d200> Battery (F05E72B0-160F-4997-AB7F-B10F7FB6B9B8)",
"<MSRectangleShape: 0x618000191d30> Path (8A682D4A-34CE-44DA-A986-BFAAFA448E48)",
"<MSShapeGroup: 0x7f82e075fac0> Fill (3AF6A505-68FE-4BAD-9BA5-4C859D8548F6)",
"<MSShapePathLayer: 0x61800017c680> Path (3A64AA1C-E554-4B86-A41D-67323D4B04D1)",
"<MSShapeGroup: 0x7f82e075fbd0> + (BA404D3E-327F-4618-81A2-4371F04482CF)",
"<MSLayerGroup: 0x6180001d3ce0> Charge (6F95F078-56BC-4FDA-A319-DE0FF8C50E13)",
"<MSRectangleShape: 0x6100001938d0> Path (BE0B6A98-1C60-4DCB-B464-526E4FAC6950)",
"<MSShapeGroup: 0x7f82e052e1c0> Notification Center Grabber (75CA34DC-7FA7-4D5B-96AB-922C23F74DC5)",
"<MSShapePathLayer: 0x610000364500> Path (332FBE18-C807-4C6E-938D-62178B9F620E)",
"<MSShapePathLayer: 0x610000364200> Path (2E267A2D-E7E0-44DB-91C1-4D79B1FE0FD8)",
"<MSShapePathLayer: 0x610000364b00> Path (BF7FAE10-2DC1-4ADF-B3D0-A851AAB969C7)",
"<MSShapeGroup: 0x7f82e052e2d0> Wifi (38D4CE87-0826-405C-B13C-D30A6EE16437)",
"<MSOvalShape: 0x61800017c740> Path (64D27B50-F968-4E57-B68E-64736A85AC85)",
"<MSShapeGroup: 0x7f82e075d910> Full (453FF4A7-D7D3-4A11-BE26-77C86E5F4016)",
"<MSOvalShape: 0x61800017c800> Path (0DD8FB65-2650-44BE-B4C6-E5CB9A76E59E)",
"<MSShapeGroup: 0x7f82e075da20> Full (9AD329E6-7ED9-48AB-946A-991EEF1E1170)",
"<MSOvalShape: 0x61800017c8c0> Path (4EA334DD-A423-4C39-B8A2-5F3656A95E73)",
"<MSShapeGroup: 0x7f82e075ced0> Full (4E2540EB-BCB8-41CB-9338-9146DC678E71)",
"<MSShapePathLayer: 0x61800017c980> Path (795A2891-D154-4E52-81F6-7FD79A9A4308)",
"<MSShapePathLayer: 0x61800017ca40> Path (F1D41D13-370E-4326-823F-A4AAABC80047)",
"<MSShapeGroup: 0x7f82e075cfe0> Empty (1002B7B5-9CD2-463E-B2A4-4883174074C2)",
"<MSShapePathLayer: 0x61800017cb00> Path (5577CC1A-9C95-45A7-89E9-AB098B6D0329)",
"<MSShapePathLayer: 0x61800017cbc0> Path (7628098C-32E7-46E7-A9F6-CBF1E2654653)",
"<MSShapeGroup: 0x7f82e075d0f0> Empty (86BBDD79-5F5D-4559-8958-002EAF3A353B)",
"<MSLayerGroup: 0x6180001d3dd0> Signal (5B08C199-0398-45CC-9905-A8B16EFB5B71)",
"<MSTextLayer: 0x7f82e052e3e0> @constraints (7E04B443-1D85-48FB-B4C6-2334FE7A6408)",
"<MSArtboardGroup: 0x7f82e074a500> iPhone 6 (8BCE4790-108A-45B3-9F4B-AE4292A8CF27)"
)
*/
組
:
MSArtboardGroup:畫板
MSShapeGroup:組里的圖層都是shape ,比如wifi
MSLayerGroup:比如局域網信號
圖層基類
:
MSLayer
http://developer.sketchapp.com/reference/MSLayer/
https://github.com/abynim/Sketch-Headers/blob/master/Headers/MSLayer.h
文本層
:
MSTextLayer
https://github.com/abynim/Sketch-Headers/blob/master/Headers/MSTextLayer.h
圖形層
:
https://github.com/abynim/Sketch-Headers/blob/master/Headers/MSShapePathLayer.h
MSOvalShape
:
MSBitmapLayer
:
http://developer.sketchapp.com/reference/MSBitmapLayer/
https://github.com/abynim/Sketch-Headers/blob/master/Headers/MSBitmapLayer.h
實現layer的autoResize屬性
1.1 獲取layer的parentGroup,parent對象可能是MSPage、MSArtboardGroup或MSLayerGroup
1.2 獲得自己的frame,手動計算縮放比例,控制。順便說一句,Sketch有個殘暴的接口:
layer.frame().scaleBy(radio);
Action
利用Sketch已經實現的一些響應接口,插件少寫代碼,得到的效果更好。
sendAction: function (commandToPerform) {
try {
// target 指定為nil,app會去尋找,響應這個消息的對象。
[NSApp sendAction:commandToPerform to:nil from:context.document];
} catch(e) {
log(e)
}
},
在Sketch-Header中可以看到到,Sketch可以響應的 Action,比如:
MSAlignLayersLeftAction.h
- (void)alignLayersLeft:(id)arg1;
MSAlignLayersRightAction.h
- (void)alignLayersRight:(id)arg1;
這些頭文件,都繼承了MSBaseAlignLayersAction。MSBaseAlignLayersAction繼承MSBaseAction。MSBaseAction繼承了NSResponder 0 0呵呵哈。
圖層中存取拓展數據
var doc = context.document;
var selection = context.selection;
var command = context.command;
var currentLayer = (selection.count() > 0) ? selection[0] : false;
var kAutoresizingMask = "kAutoresizingMask";
var content = {
kAutoresizingFlexibleLeftMargin : "AutoresizingFlexibleLeftMargin",
kAutoresizingFlexibleRightMargin : "AutoresizingFlexibleRightMargin",
kAutoresizingFlexibleTopMargin : "AutoresizingFlexibleTopMargin",
kAutoresizingFlexibleBottomMargin : "kAutoresizingFlexibleTopMargin",
kAutoresizingFlexibleWidth : "AutoresizingFlexibleWidth",
kAutoresizingFlexibleHeight : "kAutoresizingFlexibleHeight",
};
var formattedContent = JSON.stringify(content, null, "\t");
command.setValue_forKey_onLayer(formattedContent, kAutoresizingMask, currentLayer);
var constraintsForLayer = command.valueForKey_onLayer(kAutoresizingMask, currentLayer);
log(constraintsForLayer);
log(JSON.stringify(constraintsForLayer, null, "\t"));
附上本周寫的個簡單插件https://github.com/sueLan/Artboard-Mold-For-Sketch