JavaScript, HTML ve CSS ile Çizim Eklentisi Nasıl Oluşturulur (Bölüm 2)
Yayınlanan: 2022-03-10Bölüm 1'de bahsedildiği gibi, bu eğitim, Sketch uygulamasını bilen ve kullanan ve aynı zamanda kodla uğraşmaktan korkmayan kişilere yöneliktir. Bundan en iyi şekilde yararlanmak için JavaScript (ve isteğe bağlı olarak HTML/CSS) yazma konusunda en azından bazı temel deneyime sahip olmanız gerekir.
Bu öğreticinin önceki bölümünde, bir eklentiyi oluşturan temel dosyaları ve eklentinin kullanıcı arayüzünün nasıl oluşturulacağını öğrendik. Bu ikinci ve son bölümde, kullanıcı arayüzünü temel eklenti koduna nasıl bağlayacağımızı ve eklentinin ana özelliklerini nasıl uygulayacağımızı öğreneceğiz. Son olarak, kodun nasıl optimize edileceğini ve eklentinin çalışma şeklini de öğreneceğiz.
Eklentinin Kullanıcı Arayüzünü Oluşturmak: Web Arayüzümüzü ve Sketch Eklenti Kodunu Birbiriyle “Konuşmak”
Bir sonraki yapmamız gereken şey, web arayüzümüz ile Sketch eklentisi arasındaki iletişimi kurmak.
Web arayüzümüzdeki “Uygula” butonuna tıklandığında web arayüzümüzden Sketch eklentisine mesaj gönderebilmemiz gerekiyor. Bu mesajın, adım sayısı, dönüş miktarı, oluşturulacak kopya sayısı vb. gibi kullanıcının girdiği ayarlar hakkında bize bilgi vermesi gerekir.
WKWebView
bu görevi bizim için biraz daha kolaylaştırıyor: window.webkit.messageHandlers
API'sini kullanarak web arayüzümüzün JavaScript kodundan Sketch eklentimize mesajlar gönderebiliriz.
Sketch kodumuzun tarafında, eklenti web arayüzümüzden bir mesaj aldığında çağrılacak bir mesaj işleyicisini kaydetmek için başka bir yöntem, addScriptMessageHandler:name:
(veya addScriptMessageHandler_name
) kullanabiliriz.
Web kullanıcı arayüzümüzden mesaj alabileceğimizden emin olarak başlayalım. ui.js
dosyamızın createWebView
işlevine gidin ve aşağıdakileri ekleyin:
function createWebView(pageURL){ const webView = WKWebView.alloc().init(); // Set handler for messages from script const userContentController = webView.configuration().userContentController(); const ourMessageHandler = ... userContentController.addScriptMessageHandler_name( ourMessageHandler, "sketchPlugin" ); // Load page into web view webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent()); return webView; };
Burada “sketchPlugin” adını verdiğimiz bir mesaj işleyicisi eklemek için web görünümünün userContentController
özelliğini kullanıyoruz. Bu "kullanıcı içeriği denetleyicisi", mesajların web görünümümüzden karşıya geçmesini sağlayan köprüdür.
Yukarıdaki kodda garip bir şey fark etmiş olabilirsiniz: mesaj işleyicisi olarak eklediğimiz nesne, ourMessageHandler
henüz mevcut değil! Ne yazık ki, bu yöntem belirli bir tür yerel nesne beklediğinden, işleyici olarak yalnızca normal bir JavaScript nesnesi veya işlevi kullanamayız.
Neyse ki bizim için bu sınırlamayı MochaJSDelegate
kullanarak aşabiliriz, yazdığım ve normal ol 'JavaScript kullanarak ihtiyacımız olan yerel nesne türünü oluşturmayı mümkün kılan bir mini kitaplık. Sketch/MochaJSDelegate.js
altındaki eklenti paketinize manuel olarak indirmeniz ve kaydetmeniz gerekir.
Kullanmak için önce onu ui.js
içine aktarmamız gerekecek. Dosyanın en üstüne şunu ekleyin:
const MochaJSDelegate = require("./MochaJSDelegate");
Artık, addScriptMessageHandler:name:
'nin beklediği mesaj işleyicisinin türünü oluşturmak için MochaJSDelegate
kullanabiliriz:
function createWebView(pageURL){ const webView = WKWebView.alloc().init(); // Set handler for messages from script const userContentController = webView.configuration().userContentController(); const scriptMessageHandler = new MochaJSDelegate({ "userContentController:didReceiveScriptMessage:": (_, wkMessage) => { /* handle message here */ } }).getClassInstance(); userContentController.addScriptMessageHandler_name( scriptMessageHandler, "sketchPlugin" ); // Load page into web view webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent()); return webView; };
Az önce eklediğimiz kod, ihtiyacımız olan yerel nesneyi oluşturur. Ayrıca bu nesne üzerinde userContentController:didReceiveScriptMessage:
— bu yöntem daha sonra ikinci argüman olarak istediğimiz mesajla birlikte çağrılır. Henüz herhangi bir mesaj göndermediğimiz için, daha sonra buraya geri dönmemiz ve aldığımız mesajları gerçekten ayrıştırmak ve işlemek için bazı kodlar eklememiz gerekecek.
Ardından, bu mesajları bize göndermek için web arayüzümüze bazı kodlar eklememiz gerekiyor. /Resources/web-ui/script.js
adresine gidin. Kullanıcının seçeneklerini gireceği HTML <inputs />
değerlerini almayı işleyen kodun çoğunu zaten yazdığımı göreceksiniz.
Bize kalan, değerleri gerçekten gönderen kodu Sketch kodumuza eklemektir:
apply
işlevini bulun ve sonuna aşağıdakileri ekleyin:
// Send user inputs to sketch plugin window.webkit.messageHandlers.sketchPlugin.postMessage(JSON.stringify({ stepCount, startingOptions, stepOptions }));
Burada SketchPlugin olarak kaydettiğimiz ileti işleyicisine erişmek için daha önce bahsettiğimiz window.webkit.messageHandlers
API'sini sketchPlugin
. Ardından, kullanıcının girdilerini içeren bir JSON dizesiyle ona bir mesaj gönderin.
Her şeyin doğru şekilde ayarlandığından emin olalım. /Sketch/ui.js
geri dönün. Mesajları beklediğimiz gibi aldığımızdan emin olmak için, daha önce tanımladığımız yöntemi, bir mesaj aldığımızda bir iletişim kutusu gösterecek şekilde değiştireceğiz:
function createWebView(pageURL){ // ... const scriptMessageHandler = new MochaJSDelegate({ "userContentController:didReceiveScriptMessage:": (_, wkMessage) => { const UI = require("sketch/ui"); UI.alert("Hey, a message!", wkMessage.body()); } }).getClassInstance(); userContentController.addScriptMessageHandler_name( scriptMessageHandler, "sketchPlugin" ); // ... };
Şimdi eklentiyi çalıştırın (önce açtığınız mevcut herhangi bir Mozaik penceresini kapatmanız gerekebilir), bazı değerler girin ve ardından “Uygula”ya tıklayın. Aşağıdaki gibi bir uyarı görmelisiniz - bu, her şeyin doğru şekilde bağlandığı ve mesajımızın başarıyla iletildiği anlamına gelir! Değilse, önceki adımlara geri dönün ve her şeyin açıklandığı gibi yapıldığından emin olun.

Artık arayüzümüzden eklentimize mesajlar gönderebildiğimize göre, bu bilgiyle gerçekten yararlı bir şey yapan kodu yazmaya geçebiliriz: katman mozaiklerimizi oluşturmak.
Katman Mozaiklerini Oluşturma
Bunun gerçekleşmesi için neyin gerekli olduğunu değerlendirelim. İşleri biraz basitleştirirsek, kodumuzun yapması gereken şudur:
- Geçerli belgeyi bulun.
- Geçerli belgenin seçili katmanını bulun.
- Seçilen katmanı (biz buna şablon katmanı diyeceğiz) x sayıda çoğaltın.
- Her kopya için, kullanıcı tarafından belirlenen belirli değerlere (miktarlara) göre konumunu, dönüşünü, opaklığını vb. değiştirin.
Artık makul bir planımız olduğuna göre yazmaya devam edelim. Kodumuzu modülerleştirme modelimize bağlı kalarak, Sketch/
klasöründe mosaic.js
yeni bir dosya oluşturalım ve ona aşağıdaki kodu ekleyelim:
function mosaic(options){ }; module.export = mosaic;
Bu işlevi, içe aktardığımızda kullanmak için daha basit bir API sağladığından, bu modülün tek dışa aktarımı olarak kullanacağız - web arayüzünden elde ettiğimiz seçeneklerle mosaic()
'i çağırabiliriz.
Atmamız gereken ilk iki adım, mevcut belgeyi ve ardından seçilen katmanı almaktır. Sketch API, Sketch sketch/dom
modülünü içe aktararak erişebileceğimiz, belge işleme için yerleşik bir kitaplığa sahiptir. Şu anda yalnızca Document
nesnesine ihtiyacımız var, bu yüzden onu açıkça çıkaracağız. Dosyanın en üstüne şunu ekleyin:
const { Document } = require("sketch/dom");
Document
nesnesinin, özellikle kullanabileceğimiz geçerli belgeye erişmek için getSelectedDocument()
adlı bir yöntemi vardır. Geçerli belge örneğine sahip olduğumuzda, kullanıcının seçtiği katmanlara belgenin selectedLayers
özelliği aracılığıyla erişebiliriz. Ancak bizim durumumuzda, yalnızca tek katmanlı seçimleri önemsiyoruz, bu nedenle yalnızca kullanıcının seçtiği ilk katmanı alacağız:
function mosaic(options){ const document = Document.getSelectedDocument(); const selectedLayer = document.selectedLayers.layers[0]; }; module.export = mosaic;
Not: selectedLayers
kendisinin bir dizi olmasını bekliyor olabilirsiniz, ancak değil. Bunun yerine, Selection
sınıfının bir örneğidir. Bunun bir nedeni var: Selection
sınıfı, seçimi manipüle etmek için clear, map, azaltma ve forEach gibi bir dizi faydalı yardımcı yöntem içerir. layer
özelliği aracılığıyla gerçek katman dizisini ortaya çıkarır.
Kullanıcının bir belgeyi açmayı veya bir şey seçmeyi unutması durumunda da bazı uyarı geri bildirimleri ekleyelim:
const UI = require("sketch/ui"); function mosaic(options){ const document = Document.getSelectedDocument(); // Safety check: if(!document){ UI.alert("Mosaic", "️ Please select/focus a document."); return; } // Safety check: const selectedLayer = document.selectedLayers.layers[0]; if(!selectedLayer){ UI.alert("Mosaic", "️ Please select a layer to duplicate."); return; } }; module.export = mosaic;
Artık 1. ve 2. adımın kodunu yazdığımıza göre (geçerli belgeyi ve seçilen katmanı bulma), 3. ve 4. adımları ele almamız gerekiyor:
- Şablon katmanını x sayıda çoğaltın.
- Her kopya için, kullanıcı tarafından belirlenen belirli değerlere göre konumunu, dönüşünü, opaklığını vb. değiştirin.
İhtiyacımız olan tüm ilgili bilgileri options
çekerek başlayalım: çoğaltma sayısı, başlangıç seçenekleri ve adım seçenekleri. Bu özellikleri options
çıkarmak için (daha önce Document
ile yaptığımız gibi) bir kez daha yıkımı kullanabiliriz:
function mosaic(options) { // ... // Destructure options: var { stepCount, startingOptions, stepOptions } = options; }
Ardından, girdilerimizi sterilize edelim ve adım sayısının her zaman en az 1 olduğundan emin olalım:
function mosaic(options) { // ... // Destructure options: var { stepCount, startingOptions, stepOptions } = options; stepCount = Math.max(1, stepCount); }
Şimdi, şablon katmanının opaklığı, dönüşü vb.'nin tümünün kullanıcının istediği başlangıç değerleriyle eşleştiğinden emin olmamız gerekiyor. Kullanıcının seçeneklerini bir katmana uygulamak çok yapacağımız bir şey olacağından, bu çalışmayı kendi yöntemine taşıyacağız:
function configureLayer(layer, options, shouldAdjustSpacing){ const { opacity, rotation, direction, spacing } = options; layer.style.opacity = opacity / 100; layer.transform.rotation = rotation; if(shouldAdjustSpacing){ const directionAsRadians = direction * (Math.PI / 180); const vector = { x: Math.cos(directionAsRadians), y: Math.sin(directionAsRadians) }; layer.frame.x += vector.x * spacing; layer.frame.y += vector.y * spacing; } };
Ve boşluk shouldAdjustSpacing
şablon katmanına true
, yalnızca kopyalar arasına uygulanması gerektiğinden, bir false
katmanına veya olumsuzluk. Bu şekilde, döndürme ve opaklığın şablona uygulanacağını, ancak boşluk bırakılmamasını sağlayabiliriz.
mosaic
yöntemine geri dönersek, şimdi başlangıç seçeneklerinin şablon katmanına uygulandığından emin olalım:
function mosaic(options){ // ... // Configure template layer var layer = group.layers[0]; configureLayer(layer, startingOptions, false); }
Ardından, kopyalarımızı oluşturmamız gerekiyor. İlk olarak, mevcut kopya için seçeneklerin neler olduğunu izlemek için kullanabileceğimiz bir değişken oluşturalım:
function mosaic(options){ // ... var currentOptions; // ... }
Başlangıç seçeneklerini şablon katmanına zaten uyguladığımız için, bir sonraki katmana uygulanacak seçenekleri elde etmek için az önce uyguladığımız seçenekleri almalı ve stepOptions
göreli değerlerini eklemeliyiz. Bunu döngümüzde birkaç kez daha yapacağımız için, bu çalışmayı ayrıca stepOptionsBy
adlı belirli bir yönteme taşıyacağız:
function stepOptionsBy(start, step){ const newOptions = {}; for(let key in start){ newOptions[key] = start[key] + step[key]; } return newOptions; };
Bundan sonra, önceki katmanı çoğaltan, mevcut seçenekleri ona uygulayan, ardından bir sonraki çoğaltma için seçenekleri elde etmek için mevcut seçenekleri ofsetleyen (veya "adımlar") bir döngü yazmamız gerekir:
function mosaic(options) { // ... var currentOptions = stepOptionsBy(startingOptions, stepOptions); for(let i = 0; i < (stepCount - 1); i++){ let duplicateLayer = layer.duplicate(); configureLayer(duplicateLayer, currentOptions, true); currentOptions = stepOptionsBy(currentOptions, stepOptions); layer = duplicateLayer; } }
Her şey bitti - eklentimizin yapması gereken şeyin özünü başarıyla yazdık! Şimdi, kullanıcı gerçekten “Uygula” düğmesine tıkladığında mozaik kodumuzun çağrılabilmesi için bazı şeyleri bağlamamız gerekiyor.

ui.js
geri dönelim ve mesaj işleme kodumuzu ayarlayalım. Yapmamız gereken, elde ettiğimiz JSON seçenek dizisini ayrıştırmak, böylece onları gerçekten kullanabileceğimiz bir nesneye dönüştürmek. Bu seçeneklere sahip olduğumuzda, onlarla mosaic
fonksiyonunu çağırabiliriz.
İlk olarak, ayrıştırma. Aldığımız JSON mesajını ayrıştırmak için mesaj işleme fonksiyonumuzu güncellememiz gerekecek:
function createWebView(pageURL){ // ... const scriptMessageHandler = new MochaJSDelegate({ "userContentController:didReceiveScriptMessage:": (_, wkMessage) => { const message = JSON.parse(wkMessage.body()); } }); }
Ardından, bunu mosaic
fonksiyonumuza aktarmamız gerekecek. Bununla birlikte, bu gerçekten ui.js
yapması gereken bir şey değil - öncelikle arayüzle ilgili şeyleri ekranda görüntülemek için gerekli olanla ilgilenmesi gerekiyor - mozaiklerin kendisini oluşturmaması. Bu sorumlulukları ayrı tutmak için, createWebView
bir fonksiyon alan ikinci bir argüman ekleyeceğiz ve web arayüzünden seçenekler aldığımızda bu fonksiyonu çağıracağız.
Bu argümanı onApplyMessage
:
function createWebView(pageURL, onApplyMessage){ // ... const scriptMessageHandler = new MochaJSDelegate({ "userContentController:didReceiveScriptMessage:": (_, wkMessage) => { const message = JSON.parse(wkMessage.body()); onApplyMessage(message); } }); }
Ayrıca, bu onApplyMessage
argümanını alıp createWebView öğesine iletmek için dışa loadAndShow
yöntemini değiştirmemiz createWebView
:
function loadAndShow(baseURL, onApplyMessage){ // ... const webView = createWebView(pageURL, onApplyMessage); }
Son olarak, main.js
. Şimdi mosaic
işlevimizi içe aktarmamız ve eklentinin kullanıcı arayüzünden aldığımız seçeneklerle çağırmamız gerekiyor:
const mosaic = require("./mosaic"); function onRun(context){ UI.loadAndShow(context.scriptURL, options => { mosaic(options); }); };
Neredeyse tamamız!
Ancak şimdi kodumuzu çalıştırıp eklenti arayüzünde “Uygula” düğmesine tıklasaydık hiçbir şey olmazdı. Niye ya? Bunun nedeni, Sketch komut dosyalarının nasıl çalıştırıldığıdır: varsayılan olarak, yalnızca komut dosyanızın sonuna ulaşılana kadar "yaşarlar", ardından Sketch onu yok eder ve kullandığı kaynakları serbest bırakır.
Bu bizim için bir sorun çünkü mesaj almak gibi asenkron olarak (bu durumda, kodumuzun en altına ulaştıktan sonra) yapmamız gereken herhangi bir şeyin olamayacağı anlamına geliyor, çünkü komut dosyamız yok edildi. Bu, mesajlarımızı almak ve yanıtlamak için etrafta olmadığımız için web arayüzünden mesajlarımızı alamayacağımız anlamına gelir!
Fibers
kullanarak, bu noktadan sonra hayatta kalmak için komut dosyamıza ihtiyacımız olduğunu Sketch'e bildirmenin bir yolu var. Bir Fiber oluşturarak Sketch'e eşzamansız bir şey olduğunu ve komut dosyamızı etrafta tutması gerektiğini söyleriz. Sketch daha sonra komut dosyamızı yalnızca kesinlikle gerekli olduğunda yok edecektir (kullanıcının Sketch'i kapatması veya Mosaic eklentisinin güncellenmesi gerektiği gibi):
// ... const Async = require("sketch/async"); var fiber; function onRun(context){ if(!fiber){ fiber = Async.createFiber(); fiber.onCleanup(() => { UI.cleanup(); }); } UI.loadAndShow(context.scriptURL, options => { mosaic(options); }); };
işte! Şimdi eklentimizi deneyelim. Sketch'te bir katman seçiliyken, bazı ayarları girin ve ardından uygula'yı tıklayın:
Son İyileştirmeler
Artık eklentimizin işlevselliğinin çoğunu uyguladığımıza göre, biraz "uzaklaştırmayı" deneyebilir ve büyük resme bir göz atabiliriz.
Kullanıcı Deneyimini Geliştirme
Eklentiyi mevcut durumunda oynadıysanız, bir Mozaiği düzenlemeye çalıştığınızda en büyük sürtünme noktalarından birinin ortaya çıktığını fark etmiş olabilirsiniz. Bir tane oluşturduğunuzda, geri al'a basmanız, seçenekleri ayarlamanız ve ardından 'Uygula'yı tıklamanız (veya Enter tuşuna basmanız) gerekir. Ayrıca, geri alma/yineleme geçmişiniz silineceğinden, belgenizi bırakıp daha sonra geri döndükten sonra bir Mozaiği düzenlemeyi zorlaştırır ve sizi yinelenen katmanları manuel olarak silmeye bırakır.
Daha ideal bir akışta, kullanıcı sadece bir Mozaik grubu seçebilir, seçenekleri ayarlayabilir ve tam olarak aradıkları düzenlemeyi elde edene kadar Mozaik güncellemesini izleyebilir. Bunu uygulamak için çözmemiz gereken iki problemimiz var:
- İlk olarak, bir Mozaiği oluşturan kopyaları birlikte gruplandırmanın bir yoluna ihtiyacımız olacak. Sketch, bu sorunu çözmek için kullanabileceğimiz Gruplar kavramını sağlar.
- İkinci olarak, normal, kullanıcı tarafından oluşturulan bir grup ile bir Mozaik grubu arasındaki farkı söylemenin bir yoluna ihtiyacımız olacak. Sketch'in API'si ayrıca bize herhangi bir katmanda yol etiketi olarak kullanabileceğimiz ve daha sonra bir grubu 'özel' Mozaik gruplarımızdan biri olarak tanımlayabileceğimiz bilgileri depolamak için bir yol sağlar.
Bunu ele almak için önceki bölümde yazdığımız mantığı tekrar gözden geçirelim. Orijinal kodumuz aşağıdaki adımları takip eder:
- Geçerli belgeyi bulun.
- Geçerli belgenin seçili katmanını bulun.
- Seçilen katmanı (biz buna şablon katmanı diyeceğiz) x sayıda çoğaltın.
- Her kopya için, kullanıcı tarafından belirlenen belirli değerlere (miktarlara) göre konumunu, dönüşünü, opaklığını vb. değiştirin.
Yeni kullanıcı akışımızı mümkün kılmak için bu adımları şu şekilde değiştirmemiz gerekiyor:
- Geçerli belgeyi alın.
- Geçerli belgenin seçili katmanını alın.
- Seçilen katmanın Mozaik grubu olup olmadığını belirleyin.
- Başka bir katmansa, onu şablon katmanı olarak kullanın ve 4. adıma gidin.
- Bu bir Mozaik grubuysa, içindeki ilk katmanı şablon katmanı olarak kabul edin ve 5. adıma gidin.
- Şablon katmanını bir grubun içine sarın ve o grubu Mozaik grubu olarak işaretleyin.
- Şablon katmanı dışındaki tüm katmanları grubun içinden çıkarın.
- Şablon katmanını x sayıda çoğaltın.
- Her kopya için, kullanıcı tarafından belirlenen belirli değerlere göre konumunu, dönüşünü, opaklığını vb. değiştirin.
Üç yeni adımımız var. İlk yeni adım olan 3. adım için, Mozaik grubu olup olmadığını belirlemek için kendisine iletilen katmana bakacak findOrMakeSpecialGroupIfNeeded
adlı bir işlev oluşturacağız. Eğer öyleyse, sadece iade edeceğiz. Kullanıcı potansiyel olarak bir Mozaik grubunun derinliklerine yerleştirilmiş bir alt katman seçebileceğinden, aynı zamanda Mozaik gruplarımızdan biri olup olmadıklarını anlamak için seçilen katmanın ebeveynlerini de kontrol etmemiz gerekecek:
function findOrMakeSpecialGroupIfNeeded(layer){ // Loop up through the parent hierarchy, looking for a special group var layerToCheck = layer; while(layerToCheck){ if(/* TODO: is mosaic layer? */){ return layerToCheck; } layerToCheck = layerToCheck.parent; } };
Eğer bir Mozaik grubu bulamazsak, geçirdiğimiz katmanı bir Group
içine sararız ve sonra onu bir Mozaik grubu olarak etiketleriz.
Dosyanın başına dönersek, şimdi Grup sınıfını da çıkarmamız gerekecek:
const { Document, Group } = require("sketch/dom");
function findOrMakeSpecialGroupIfNeeded(layer){ // Loop up through the parent hierarchy, looking for a special group var layerToCheck = layer; while(layerToCheck){ if(/* TODO: is mosaic layer? */){ return layerToCheck; } layerToCheck = layerToCheck.parent; } // Group const destinationParent = layer.parent; const group = new Group({ name: "Mosaic Group", layers: [ layer ], parent: destinationParent }); /* TODO: mark group as mosaic layer */ return group; };
Şimdi boşlukları (yapılacaklar) doldurmamız gerekiyor. Başlangıç olarak, bir grubun bize ait özel gruplardan biri olup olmadığını belirlemenin bir yoluna ihtiyacımız var. Burada Sketch kütüphanesinin Settings
modülü imdadımıza yetişiyor. Özel bilgileri belirli bir katmanda depolamak ve aynı zamanda geri okumak için kullanabiliriz.
Dosyanın en üstündeki modülü içe aktardığımızda:
const Settings = require("sketch/settings");
Ardından, bir katmandaki verileri ayarlamak ve okumak için setLayerSettingForKey
ve layerSettingForKey
adlı iki temel yöntemi kullanabiliriz:
function findOrMakeSpecialGroupIfNeeded(layer){ const isSpecialGroupKey = "is-mosaic-group"; // Loop up through the parent hierarchy, looking for a special group var layerToCheck = layer; while(layerToCheck){ let isSpecialGroup = Settings.layerSettingForKey(layerToCheck, isSpecialGroupKey); if(isSpecialGroup) return layerToCheck; layerToCheck = layerToCheck.parent; } // Group const destinationParent = layer.parent; layer.remove(); // explicitly remove layer from it's existing parent before adding it to group const group = new Group({ name: "Mosaic Group", layers: [ layer ], parent: destinationParent }); Settings.setLayerSettingForKey(group, isSpecialGroupKey, true); return group; };
Artık bir mozaik grubundaki bir katmanı sarmayı işleyen bir yöntemimiz olduğuna göre (veya zaten bir mozaik grubuysa, yalnızca onu döndürür), güvenlik kontrollerimizden hemen sonra onu ana mosaic
yöntemimize ekleyebiliriz:
function mosaic(options){ // ... safety checks ... // Group selection if needed: const group = findOrMakeSpecialGroupIfNeeded(selectedLayer); }
Ardından, şablon katmanı (ilk katman olan) dışındaki tüm katmanları gruptan kaldırmak için bir döngü ekleyeceğiz:
function mosaic(options) { // ... // Remove all layers except the first: while(group.layers.length > 1){ group.layers[group.layers.length - 1].remove(); } }
Son olarak, kullanıcı eski grup içinde yuvalanmış bir katmanı (kaldırmış olabileceğimiz bir katman) orijinal olarak seçmiş olabileceğinden, grubun boyutunun yeni içeriğine uygun olduğundan emin olacağız.
Ayrıca mevcut seçimi mozaik grubumuzun kendisine ayarladığınızdan emin olmamız gerekecek. Bu, kullanıcı aynı mozaik grubunda bir dizi hızlı değişiklik yapıyorsa, seçiminin kaldırılmamasını sağlayacaktır. Bir katmanı çoğaltmak için yazdığımız koddan sonra şunu ekleyin:
function mosaic(options) { // ... // Fit group to duplicates group.adjustToFit(); // Set selection to the group document.selectedLayers.clear(); group.selected = true; }
Eklentiyi tekrar deneyin. Mozaik düzenlemenin artık çok daha yumuşak olduğunu görmelisiniz!
Arayüzü Geliştirme
Fark edebileceğiniz başka bir şey de, her ikisinin de aynı anda görünür hale gelmesi açısından, görüntüleme penceresi ve içindeki arayüz arasındaki senkronizasyon eksikliğidir. Bunun nedeni, pencereyi görüntülediğimizde, web arayüzünün yüklenmesinin bittiğinin garanti edilmemesidir, bu nedenle bazen daha sonra "açılır" veya "yanıp söner".
Bunu düzeltmenin bir yolu, web arayüzünün yüklenmesinin ne zaman bittiğini dinlemek ve ancak bundan sonra penceremizi göstermektir. Geçerli sayfanın yüklenmesi bittiğinde WKWebView'ün çağıracağı webView webView:didFinishNavigation:
adlı bir yöntem vardır. Tam olarak aradığımız bildirimi almak için kullanabiliriz.
ui.js
geri döndüğümüzde, bu yöntemi uygulamak için oluşturduğumuz MochaJSDelegate
örneğini genişleteceğiz ve bu da createWebView öğesine onLoadFinish
argümanını createWebView
:
function createWebView(pageURL, onApplyMessage, onLoadFinish){ const webView = WKWebView.alloc().init(); // Create delegate const delegate = new MochaJSDelegate({ "webView:didFinishNavigation:": (webView, navigation) => { onLoadFinish(); }, "userContentController:didReceiveScriptMessage:": (_, wkMessage) => { const message = JSON.parse(wkMessage.body()); onApplyMessage(message); } }).getClassInstance(); // Set load complete handler webView.navigationDelegate = delegate; // Set handler for messages from script const userContentController = webView.configuration().userContentController(); userContentController.addScriptMessageHandler_name(delegate, "sketchPlugin"); // Load page into web view webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent()); return webView; };
loadAndShow
yöntemine geri dönersek, onu yalnızca web görünümü yüklendikten sonra pencereyi gösterecek şekilde ayarlayacağız:
function loadAndShow(baseURL, onApplyMessage){ // ... const window = createWindow(); const webView = createWebView(pageURL, onApplyMessage, () => { showWindow(window); }); window.contentView = webView; _window = window; };
Bingo! Artık penceremiz yalnızca web görünümünün yüklenmesi bittiğinde görüntüleniyor ve bu sinir bozucu görsel titremeyi önlüyor.
Çözüm
Tebrikler, ilk Sketch eklentinizi oluşturdunuz!
Mosaic'i kurmak ve onunla oynamak isterseniz, eklentinin tamamını GitHub'dan indirebilirsiniz. Ve gitmeden önce, yolculuğunuzun geri kalanında işinize yarayabilecek birkaç kaynak:
- geliştirici.sketchapp.com Sketch eklentisi geliştirme ile ilgili resmi kaynak. Birkaç faydalı kılavuzun yanı sıra Sketch JavaScript kitaplığı için bir API referansı içerir.
- Sketchplugins.com Sketch eklentisi geliştiricilerinden oluşan harika ve yardımsever bir topluluk. Tüm yakıcı sorularınızın yanıtını almak için harika.
- github.com/sketchplugins/plugin-directory Resmi, Sketch eklentilerinin merkezi GitHub deposu. Eklentilerinizi buraya gönderebilir ve Sketch topluluğunun geri kalanıyla paylaşabilirsiniz!