Fermer

juillet 8, 2019

Comment construire un plugin d'esquisse avec JavaScript, HTML et CSS (partie 2)


Dans cette deuxième partie de notre didacticiel sur la création de plug-ins Sketch, nous allons reprendre là où nous en sommes restés avec la construction de notre interface utilisateur, puis nous passerons à la fonction clé de générer nos mosaïques de couches et optimisation du code du plugin final.

Comme indiqué dans la 1ère partie ce didacticiel est destiné aux personnes qui connaissent et utilisent l'application Sketch et qui n'ont pas peur de manipuler le code. Pour en tirer le meilleur parti, vous devez avoir au moins une expérience de base de l'écriture de JavaScript (et, éventuellement, de HTML / CSS).

Dans la partie précédente de ce didacticiel, nous avons découvert les fichiers de base qui constituent un plugin, et comment créer l'interface utilisateur du plugin. Dans cette deuxième et dernière partie, nous allons apprendre à connecter l’interface utilisateur au code du plugin principal et à mettre en œuvre les principales fonctionnalités de ce dernier. Enfin, nous allons également apprendre à optimiser le code et le fonctionnement du plug-in.

Création de l'interface utilisateur du plug-in: Création de notre interface Web et du code de plug-in Sketch «Parlez» entre eux

Nous devons ensuite configurer la communication entre notre interface Web et le plug-in Sketch.

Nous devons pouvoir envoyer un message de notre interface Web au plug-in Sketch lorsque le bouton "Appliquer" de notre interface Web est cliqué. Ce message doit nous indiquer les paramètres saisis par l'utilisateur (nombre d'étapes, montant de la rotation, nombre de doublons à créer, etc.)

WKWebView simplifie un peu cette tâche. plus facile pour nous: nous pouvons envoyer des messages à notre plug-in Sketch à partir du code JavaScript de notre interface Web en utilisant l'API window.webkit.messageHandlers .

Du côté de notre code Sketch, nous pouvons utiliser une autre méthode, addScriptMessageHandler: name: (ou addScriptMessageHandler_name ) pour enregistrer un gestionnaire de messages qui sera appelé chaque fois qu'il reçoit un message envoyé depuis notre interface Web de plug-in.

Commençons par vérifier que nous pouvons le faire. recevoir des messages de notre interface Web. Rendez-vous à la fonction de createWebView du fichier ui.js et ajoutez ce qui suit:

 fonction createWebView (pageURL) {
        const webView = WKWebView.alloc (). init ();

        // Définit le gestionnaire pour les messages du script

        const userContentController = webView.configuration (). userContentController ();
        
        const ourMessageHandler = ...

        userContentController.addScriptMessageHandler_name (
                notreMessageHandler, "sketchPlugin"
        )

        // Charger la page en vue Web

        webView.loadFileURL_allowingReadAccessToURL (pageURL, pageURL.URLByDeletingLastPathComponent ());

        retourner webView;
};

Nous utilisons ici la propriété userContentController de la vue Web pour ajouter un gestionnaire de messages que nous avons nommé “sketchPlugin”. Ce «contrôleur de contenu utilisateur» est le pont qui garantit la transmission des messages depuis notre vue Web.

Vous avez peut-être remarqué quelque chose d'étrange dans le code ci-dessus: l'objet que nous ajoutons en tant que gestionnaire de messages, ourMessageHandler n'existe pas encore! Malheureusement, nous ne pouvons pas simplement utiliser un objet ou une fonction JavaScript classique comme gestionnaire, car cette méthode attend un certain type d'objet natif.

Heureusement pour nous, nous pouvons contourner cette limitation en utilisant MochaJSDelegate [19659017]une mini-bibliothèque que j’ai écrite et qui permet de créer le type d’objet natif dont nous avons besoin en utilisant JavaScript traditionnel. Vous devez manuellement télécharger et l'enregistrer dans votre paquet de plugins sous Sketch / MochaJSDelegate.js .

Pour pouvoir l'utiliser, nous allons d'abord devoir l'importer into ui.js . Ajoutez ce qui suit en haut du fichier:

 const MochaJSDelegate = require ("./ MochaJSDelegate");

Nous pouvons maintenant utiliser MochaJSDelegate pour créer le type de gestionnaire de messages addScriptMessageHandler: nom: attend:

 function createWebView (pageURL) {
        const webView = WKWebView.alloc (). init ();

        // Définit le gestionnaire pour les messages du script

        const userContentController = webView.configuration (). userContentController ();

        const scriptMessageHandler = new MochaJSDelegate ({
                "userContentController: didReceiveScriptMessage:": (_, wkMessage) => {
                        / * gérer le message ici * /
                }
        }). getClassInstance ();

        userContentController.addScriptMessageHandler_name (
                scriptMessageHandler, "sketchPlugin"
        )

        // Charger la page en vue Web

        webView.loadFileURL_allowingReadAccessToURL (pageURL, pageURL.URLByDeletingLastPathComponent ());

        retourner webView;
};

Le code que nous venons d'ajouter crée l'objet natif dont nous avons besoin. Elle définit également une méthode sur cet objet nommée userContentController: didReceiveScriptMessage: - cette méthode est ensuite appelée avec le message que nous voulons comme second argument. Comme nous n’envoyons pas encore de messages, nous devrons revenir ici plus tard et ajouter du code pour analyser et traiter les messages que nous recevons.

Nous devons ensuite ajouter du code à notre interface Web pour nous envoyer ces messages. Rendez-vous sur /Resources/web-ui/script.js . Vous constaterez que j'ai déjà écrit la plupart du code traitant de l'extraction des valeurs du code HTML dans lequel l'utilisateur entrera ses options.

Il ne nous reste plus qu'à ajouter le code qui envoie réellement le code les valeurs dans notre code d'esquisse:

Recherchez la fonction appliquez-y et ajoutez ce qui suit à la fin de celle-ci:

 // Envoyez les entrées utilisateur au plug-in sketch

window.webkit.messageHandlers.sketchPlugin.postMessage (JSON.stringify ({
        stepCount, startOptions, stepOptions
}));

Nous utilisons ici window.webkit.messageHandlers API mentionnée précédemment pour accéder au gestionnaire de messages que nous avons enregistré ci-dessus sous le nom sketchPlugin . Envoyez-lui ensuite un message avec une chaîne JSON contenant les entrées de l’utilisateur.

Assurez-vous que tout est configuré correctement. Retournez à /Sketch/ui.js . Afin de nous assurer que les messages que nous recevons sont corrects, nous allons modifier la méthode définie précédemment afin qu'elle affiche une boîte de dialogue lorsque nous recevons le message suivant:

 function createWebView (pageURL) {
        // ...

        const scriptMessageHandler = new MochaJSDelegate ({
                "userContentController: didReceiveScriptMessage:": (_, wkMessage) => {
                        const UI = require ("sketch / ui");
                        
                        UI.alert ("Hey, un message!", WkMessage.body ());
                }
        }). getClassInstance ();

        userContentController.addScriptMessageHandler_name (
                scriptMessageHandler, "sketchPlugin"
        )

        // ...
};

Maintenant, lancez le plug-in (vous devrez peut-être d'abord fermer toute fenêtre de mosaïque existante que vous avez ouverte), entrez des valeurs, puis cliquez sur «Appliquer». Vous devriez voir une alerte comme celle ci-dessous - cela signifie que tout est câblé correctement et que notre message a été transmis avec succès! Sinon, revenez sur les étapes précédentes et assurez-vous que tout a été effectué comme décrit.

 Image indiquant le dialogue à afficher après avoir cliqué sur le bouton "Appliquer" de l'interface utilisateur du plug-in.
Le dialogue que vous devriez voir apparaître une fois vous cliquez sur Appliquer. ( Grand aperçu )

Maintenant que nous pouvons envoyer des messages de notre interface à notre plugin, nous pouvons passer à l'écriture du code qui fait réellement quelque chose d'utile avec cette information: générer nos mosaïques de calque

Génération des mosaïques de calque

Faisons le point sur ce qui est nécessaire pour que cela se produise. Notre code doit simplifier les choses:

  1. Trouver le document actuel.
  2. Trouver le calque sélectionné du document actuel.
  3. Dupliquez le calque sélectionné (nous l'appellerons le modèle ]. couche) x nombre de fois.
  4. Pour chaque duplicata, modifiez sa position, sa rotation, son opacité, etc., à l'aide des valeurs spécifiques (montants) définies par l'utilisateur.

plan, continuons à écrire. En nous en tenant à notre modèle de modularisation de notre code, créons un nouveau fichier, mosaic.js dans le dossier Sketch / et ajoutons-y le code suivant:

 function mosaic ( options) {

};

module.export = mosaïque;

Nous utiliserons cette fonction comme seule exportation de ce module, car elle simplifie l'utilisation de l'API une fois importée. Nous pouvons simplement appeler mosaic () avec les options que nous recevons du interface Web.

Les deux premières étapes à suivre sont l’obtention du document actuel, puis de son calque sélectionné. L'API Sketch possède une bibliothèque intégrée pour la manipulation de documents, à laquelle vous pouvez accéder en important le module sketch / dom . Nous avons seulement besoin de l’objet Document pour le moment, nous allons donc le retirer explicitement. En haut du fichier, ajoutez:

 const {Document} = require ("sketch / dom");

L'objet Document dispose d'une méthode permettant d'accéder au document actuel que nous pouvons utiliser, appelée getSelectedDocument () . Une fois que nous avons l’instance de document en cours, nous pouvons accéder aux couches sélectionnées par l’utilisateur via la propriété selectedLayers du document. Dans notre cas, cependant, nous ne nous intéressons qu'aux sélections à une seule couche. Nous ne saisirons donc que la première couche sélectionnée par l'utilisateur:

 mosaic function (options) {
        const document = Document.getSelectedDocument ();
        const selectedLayer = document.selectedLayers.layers [0];
};

module.export = mosaïque;

Note: Vous vous attendiez peut-être à ce que selectedLayers soit lui-même un ensemble, mais ce n'est pas le cas. C’est plutôt un exemple de la classe Selection . Il y a une raison à cela: la classe Selection contient un tas de méthodes utiles pour manipuler la sélection, telles que effacer, mapper, réduire et forEach . Il expose le tableau de couches réel via la propriété layer .

Ajoutons également un retour d'avertissement si l'utilisateur oublie d'ouvrir un document ou de sélectionner un élément:

 const UI = require ("sketch / ui");

mosaïque de fonctions (options) {
        const document = Document.getSelectedDocument ();

        //        Contrôle de sécurité:

        si (! document) {
                UI.alert ("Mosaïque", "⚠️ Veuillez sélectionner / mettre au point un document.");

                revenir;
        }

        //        Contrôle de sécurité:

        const selectedLayer = document.selectedLayers.layers [0];

        si (! selectedLayer) {
                UI.alert ("Mosaïque", "⚠️ Sélectionnez une couche à dupliquer.");
                
                revenir;
        }
};

module.export = mosaïque;

Maintenant que nous avons écrit le code pour les étapes 1 et 2 (recherche du document actuel et du calque sélectionné), nous devons aborder les étapes 3 et 4:

  • Dupliquez le calque du modèle x nombre de fois.
  • Pour chaque duplicata, modifiez sa position, sa rotation, son opacité, etc., en fonction des valeurs spécifiques définies par l'utilisateur.

Commençons par extraire toutes les informations pertinentes dont nous avons besoin parmi les options : fois à dupliquer, options de départ et options d’étape. Nous pouvons à nouveau utiliser la déstructuration (comme nous l'avons fait précédemment avec le Document ) pour extraire ces propriétés des options :

 fonction mosaïque (options) {
        // ...
        
        // options de destruction:

        var {stepCount, startingOptions, stepOptions} = options;
}

Désinfectons ensuite nos entrées et veillons à ce que le nombre de pas soit toujours au moins égal à 1: mosaïque de fonctions

 (options) {
        // ...
        
        // options de destruction:
        
        var {stepCount, startingOptions, stepOptions} = options;
        
        stepCount = Math.max (1, stepCount);
}

Nous devons maintenant nous assurer que l’opacité, la rotation, etc. du calque du modèle correspondent aux valeurs de départ souhaitées par l’utilisateur. Comme nous allons en faire beaucoup, appliquer les options de l'utilisateur à une couche sera transféré à sa propre méthode:

 function configureLayer (layer, options, shouldAdjustSpacing) {
        const {opacité, rotation, direction, espacement} = options;

        layer.style.opacity = opacity / 100;
        layer.transform.rotation = rotation;

        if (shouldAdjustSpacing) {
                const directionAsRadians = direction * (Math.PI / 180);
                vecteur const = {
                        x: Math.cos (directionAsRadians),
                        y: Math.sin (directionAsRadians)
                };

                layer.frame.x + = vector.x * spacing;
                layer.frame.y + = vector.y * spacing;
        }
};

Et comme l'espacement doit uniquement être appliqué entre les doublons et non le calque de modèle, nous avons ajouté un drapeau spécifique, shouldAdjustSpacing que nous pouvons définir sur true . ou false selon que nous appliquons des options à un calque de modèle ou non. De cette façon, nous pouvons nous assurer que la rotation et l'opacité seront appliquées au modèle, mais pas à l'espacement.

Dans la méthode mosaic assurons maintenant que les options de départ sont appliquées au calque du modèle: 19659019] mosaïque de fonctions (options) {
        // ...
        
        // Configurer la couche de modèle

        var layer = group.layers [0];
        
        configureLayer (layer, startingOptions, false);
}

Ensuite, nous devons créer nos doublons. Commençons par créer une variable que nous pouvons utiliser pour suivre les options du duplicata actuel:

 mosaic function (options) {
        // ...

        var currentOptions; // ...
}

Puisque nous avons déjà appliqué les options de départ au calque modèle, nous devons prendre les options que nous venons d'appliquer et ajouter les valeurs relatives de stepOptions afin d'obtenir les options à appliquer au calque suivant. Comme nous le ferons également plusieurs fois dans notre boucle, nous déplacerons également ce travail dans une méthode spécifique, stepOptionsBy :

fonction stepOptionsBy (start, step) {
        const newOptions = {};
        
        pour (laisser la touche commencer) {
                newOptions [key] = début [key] + étape [key];
        }

        renvoyer newOptions;
};

Après cela, nous devons écrire une boucle qui duplique le calque précédent, y applique les options actuelles, puis décale (ou “étapes”) les options actuelles pour obtenir les options du duplicata suivant:

 mosaïque de fonctions (options) {
        // ...
        
        var currentOptions = stepOptionsBy (startupOptions, stepOptions);

        for (let i = 0; i 

Tout est terminé – nous avons écrit avec succès l'essentiel de ce que notre plug-in est censé faire! Nous devons maintenant câbler les choses de manière à ce que l'utilisateur clique sur le bouton «Appliquer» notre code mosaïque est invoqué.

Revenons à ui.js et ajustons notre code de gestion des messages. Nous devrons analyser la chaîne d'options JSON que nous obtenons afin qu'elles Nous pouvons maintenant utiliser la fonction mosaic avec elle pour les utiliser.

D'abord, l'analyse, nous devrons mettre à jour notre fonction de traitement des messages. pour analyser le message JSON obtenu:

 function createWebView (pageURL) {
        // ...
        
        const scriptMessageHandler = new MochaJSDelegate ({
                "userContentController: didReceiveScriptMessage:": (_, wkMessage) => {
                        const message = JSON.parse (wkMessage.body ());
                }
        });
}

Nous devrons ensuite passer à notre fonction mosaïque . Cependant, ce n'est pas vraiment ce que notre code dans ui.js devrait faire – il est censé être principalement concerné par ce qui est nécessaire pour afficher des éléments liés à l'interface à l'écran – ne pas créer de mosaïques. Pour que ces responsabilités restent séparées, nous allons ajouter un deuxième argument à createWebView qui prend une fonction, et nous l'appellerons chaque fois que nous recevrons des options de l'interface Web.

Appelons cet argument onApplyMessage : Fonction

 createWebView (pageURL, onApplyMessage) {
        // ...
        
        const scriptMessageHandler = new MochaJSDelegate ({
                "userContentController: didReceiveScriptMessage:": (_, wkMessage) => {
                        const message = JSON.parse (wkMessage.body ());
                        
                        onApplyMessage (message);
                }
        });
}

Nous devrons également modifier notre méthode exportée, loadAndShow pour prendre cet argument onApplyMessage également et le transmettre à createWebView :

. ] fonction loadAndShow (baseURL, onApplyMessage) {
        // ...
        
        const webView = createWebView (pageURL, onApplyMessage);
}

Enfin, dirigez-vous sur main.js . Nous devons maintenant importer notre fonction mosaic et l’appeler avec les options reçues depuis l’interface utilisateur du plug-in:

 const mosaic = require ("./ mosaic");

fonction onRun (contexte) {
        UI.loadAndShow (context.scriptURL, options => {
                mosaïque (options);
        });
};

Nous avons presque terminé!

Toutefois, si nous exécutions notre code maintenant et cliquions sur le bouton "Appliquer" de l'interface du plug-in, rien ne se passerait. Pourquoi? La raison en est due à la façon dont les scripts Sketch sont exécutés: par défaut, ils "ne vivent" que jusqu'à ce que le bas de votre script soit atteint, après quoi Sketch le détruit et libère les ressources qu'il utilisait.

C'est un problème pour nous car cela signifie que tout ce dont nous avons besoin doit se produire de manière asynchrone (dans ce cas, c'est après que le bas de notre code est atteint), tout comme la réception de messages, ne peut pas, car notre script a été détruit. Cela signifie que nous n'obtiendrions aucun de nos messages via l'interface Web, car nous ne sommes pas là pour les recevoir et y répondre!

Il existe un moyen de signaler à Sketch que nous avons besoin que notre script reste en vie à partir de maintenant, utilisant Fibres . En créant une fibre, nous indiquons à Sketch qu'un événement asynchrone est en cours et qu'il doit conserver notre script. Sketch ne détruira alors notre script qu'en cas d'absolue nécessité (comme l'utilisateur qui ferme Sketch ou lorsque le plugin Mosaic doit être mis à jour):

 // ...

const Async = require ("sketch / async");

fibre var;

fonction onRun (contexte) {
    si (! fibre) {
        fibre = Async.createFiber ();
        fibre.onCleanup (() => {
            UI.cleanup ();
        });
    }
    
    UI.loadAndShow (context.scriptURL, options => {
        mosaïque (options);
    });
};

Voilà! Essayons maintenant notre plugin. Avec un calque sélectionné dans Sketch, entrez quelques paramètres, puis cliquez sur appliquer:

Essayons maintenant notre plugin – avec un calque sélectionné dans Sketch, entrez quelques paramètres, puis cliquez sur «Appliquer».

Améliorations finales

Maintenant que la plupart des fonctionnalités de notre plugin sont implémentées, nous pouvons essayer de faire un zoom arrière et jeter un coup d'œil à la situation dans son ensemble.

Améliorer l'expérience de l'utilisateur

Si vous avez déjà joué avec Dans l'état actuel du plug-in, vous avez peut-être remarqué que l'un des plus gros points de friction apparaît lorsque vous essayez de modifier une mosaïque. Une fois que vous en avez créé un, vous devez appuyer sur undo, ajuster les options, puis cliquer sur ‘Apply’ (ou appuyer sur Entrée). Cela rend également plus difficile la modification d'une mosaïque une fois que vous avez quitté votre document et y êtes revenu plus tard, car votre historique d'annulation / restauration aura été effacé, ce qui vous permettra de supprimer manuellement les calques dupliqués vous-même.

flux idéal, l’utilisateur peut simplement sélectionner un groupe de mosaïque, ajuster les options et regarder la mise à jour de la mosaïque jusqu’à obtenir l’arrangement exact qu’il recherche. Pour mettre cela en œuvre, nous avons deux problèmes à résoudre:

  1. Premièrement, nous aurons besoin d’un moyen de regrouper les doublons qui constituent une mosaïque. Sketch fournit le concept de groupes, que nous pouvons utiliser pour résoudre ce problème.
  2. Deuxièmement, nous aurons besoin d’un moyen de faire la différence entre un groupe normal créé par l’utilisateur et un groupe de mosaïque. L'API de Sketch nous fournit également un moyen de stocker des informations sur une couche donnée, que nous pouvons utiliser comme balises de chemin et identifier ensuite un groupe comme l'un de nos groupes de mosaïques "spéciaux".

Revenons à la logique décrite précédemment. section pour répondre à cela. Notre code d'origine suit les étapes suivantes:

  1. Trouver le document actuel.
  2. Trouver le calque sélectionné du document actuel.
  3. Dupliquez le calque sélectionné (nous l'appellerons le calque modèle ) x
  4. Pour chaque duplicata, modifiez sa position, sa rotation, son opacité, etc., à l'aide des valeurs spécifiques (montants) définies par l'utilisateur.

Afin de rendre notre nouveau flux d'utilisateur possible, nous devons: Procédez comme suit:

  1. Saisissez le document actuel.
  2. Saisissez le calque sélectionné du document actuel.
  3. Déterminez si le calque sélectionné est un groupe de mosaïque ou non.
    • S'il s'agit d'un autre calque, utilisez-le comme la couche de modèle et passez à l'étape 4.
    • Si est un groupe de mosaïques considérez la première couche en tant que couche modèle et passez à l'étape 5.

    [19659038] Insérez le calque de modèle dans un groupe et marquez ce groupe en tant que groupe de mosaïque.

  4. Supprimez tous les calques de ce groupe, sauf le calque du modèle.
  5. Dupliquez le calque du modèle x nombre de fois.
  6. Pour chaque duplicata, modifiez sa position, sa rotation, son opacité, etc., en utilisant les valeurs spécifiques définies par l'utilisateur.

Nous avons trois nouvelles étapes. Pour la première nouvelle étape, l’étape 3, nous allons créer une fonction nommée findOrMakeSpecialGroupIfNeeded qui examinera la couche qui lui a été transférée pour déterminer s’il s’agit ou non d’un groupe Mosaic. Si c'est le cas, nous le renverrons. Etant donné que l'utilisateur peut potentiellement sélectionner une sous-couche imbriquée profondément dans un groupe Mosaic, nous devrons également vérifier les parents de la couche sélectionnée pour savoir s'ils font également partie de nos groupes Mosaic:

 function findOrMakeSpecialGroupIfNeeded (layer) {
        // Boucle dans la hiérarchie parente à la recherche d'un groupe spécial

        var layerToCheck = couche;

        while (layerToCheck) {
                si (/ * TODO: est la couche de mosaïque? * /) {
                        retourner layerToCheck;
                }

                layerToCheck = layerToCheck.parent;
        }
};

Si nous ne parvenons pas à trouver un groupe de mosaïque, nous allons simplement envelopper le calque qui nous a été transmis à l'intérieur d'un groupe puis l'identifier en tant que groupe de mosaïque.

Retour en haut de page le fichier, nous allons aussi devoir extraire la classe Group:

 const {Document, Group} = require ("sketch / dom");
 function findOrMakeSpecialGroupIfNeeded (couche) {
        // Boucle dans la hiérarchie parente à la recherche d'un groupe spécial

        var layerToCheck = couche;

        while (layerToCheck) {
                si (/ * TODO: est la couche de mosaïque? * /) {
                        retourner layerToCheck;
                }

                layerToCheck = layerToCheck.parent;
        }
        
        // groupe

        const destinationParent = layer.parent;
        groupe const = nouveau groupe ({
                nom: "groupe mosaïque",
                couches: [ layer ],
                parent: destinationParent
        });
        
        / * TODO: marque le groupe comme couche de mosaïque * /
        
        groupe de retour;
};

Nous devons maintenant combler les lacunes (todo’s). Pour commencer, nous avons besoin d’un moyen d’identifier si un groupe est ou non l’un des groupes spéciaux qui nous appartiennent ou non. Ici, le module Settings de la bibliothèque Sketch vient à notre secours. Nous pouvons l'utiliser pour stocker des informations personnalisées sur un calque particulier, ainsi que pour les relire.

Une fois le module importé en haut du fichier:

 const Settings = require ("sketch / settings");

Nous pouvons ensuite utiliser deux méthodes clés fournies, setLayerSettingForKey et layerSettingForKey pour définir et lire les données d'une couche:

 function findOrMakeSpecialGroupIfNeeded (layer)
        const isSpecialGroupKey = "is-mosaic-group";

        // Boucle dans la hiérarchie parente à la recherche d'un groupe spécial

        var layerToCheck = couche;

        while (layerToCheck) {
                let isSpecialGroup = Settings.layerSettingForKey (layerToCheck, isSpecialGroupKey);

                if (isSpecialGroup) renvoie layerToCheck;

                layerToCheck = layerToCheck.parent;
        }
        
        // groupe

        const destinationParent = layer.parent;

       layer.remove (); // supprime explicitement la couche de son parent existant avant de l'ajouter au groupe

        groupe const = nouveau groupe ({
                nom: "groupe mosaïque",
                couches: [ layer ],
                parent: destinationParent
        });
        
        Settings.setLayerSettingForKey (groupe, isSpecialGroupKey, true);

        groupe de retour;
};

Maintenant que nous avons une méthode qui recouvre l'enveloppe d'un calque dans un groupe de mosaïque (ou, si déjà un groupe de mosaïque, le retourne), nous pouvons maintenant l'insérer dans notre méthode principale de mosaïque après nos contrôles de sécurité:

 mosaïque de fonctions (options) {
        // ... contrôles de sécurité ...

        // Sélection du groupe si nécessaire:

        groupe const = findOrMakeSpecialGroupIfNeeded (selectedLayer);
}

Nous allons ensuite ajouter une boucle pour supprimer toutes les couches du groupe, à l’exception de la couche modèle (la première):

 mosaic function (options) {
        // ...
        
        // Supprime tous les calques sauf le premier:
        
        while (group.layers.length> 1) {
                groupe.layers [group.layers.length - 1] .remove ();
        }
}

Enfin, nous nous assurerons que la taille du groupe est adaptée à son nouveau contenu, car l'utilisateur aurait peut-être initialement sélectionné un calque imbriqué dans l'ancien groupe (un calque que nous aurions peut-être supprimé).

Vous devez également vous assurer de définir la sélection actuelle sur notre groupe de mosaïque lui-même. Cela garantira que, si l'utilisateur apporte de nombreuses modifications rapides au même groupe de mosaïques, il ne sera pas désélectionné. Après le code que nous avons déjà écrit pour dupliquer un calque, ajoutez:

 mosaic function (options) {
        // ...
        
        // Ajuster le groupe aux doublons

        group.adjustToFit ();

        // Définir la sélection sur le groupe

        document.selectedLayers.clear ();
        group.selected = true;
}

Essayez à nouveau le plugin. Vous devriez trouver que l'édition d'une mosaïque est beaucoup plus fluide maintenant!

Amélioration de l'interface

Une autre chose que vous remarquerez peut-être est le manque de synchronisation entre la fenêtre d'affichage et l'interface à l'intérieur de celle-ci. le même temps. Cela est dû au fait que, lorsque nous affichons la fenêtre, le chargement du navigateur n’est pas garanti, il est donc parfois difficile de faire apparaître un «pop» ou un «flash» par la suite.

Un moyen de résoudre ce problème consiste à: écoute lorsque le chargement de l'interface Web est terminé, puis seulement pour afficher notre fenêtre. Il existe une méthode, webView: didFinishNavigation: que WKWebView appellera lorsque le chargement de la page en cours sera terminé. Nous pouvons l'utiliser pour obtenir exactement la notification que nous recherchons.

En ui.js nous étendrons l'instance de MochaJSDelegate pour implémenter cette méthode, qui appellera à son tour l'argument onLoadFinish que nous allons passer à createWebView :

 function createWebView (pageURL, onApplyMessage, onLoadFinish) {
        const webView = WKWebView.alloc (). init ();

        // Créer un délégué

        const delegate = new MochaJSDelegate ({
                "webView: didFinishNavigation:": (webView, navigation) => {
                        onLoadFinish ();
                },
                "userContentController: didReceiveScriptMessage:": (_, wkMessage) => {
                        const message = JSON.parse (wkMessage.body ());
                        
                        onApplyMessage (message);
                }
        }). getClassInstance ();

        // Définit le gestionnaire de chargement complet

        webView.navigationDelegate = délégué;

        // Définit le gestionnaire pour les messages du script

        const userContentController = webView.configuration (). userContentController ();

        userContentController.addScriptMessageHandler_name (delegate, "sketchPlugin");

        // Charger la page en vue Web

        webView.loadFileURL_allowingReadAccessToURL (pageURL, pageURL.URLByDeletingLastPathComponent ());

        retourner webView;
};

Et dans la méthode loadAndShow nous allons l’ajuster afin qu’elle ne montre la fenêtre que lorsque la vue Web a été chargée:

 function loadAndShow (baseURL, onApplyMessage) {
        // ...

        const window = createWindow ();
        const webView = createWebView (pageURL, onApplyMessage, () => {
                showWindow (fenêtre);
        });

        window.contentView = webView;

        _window = window;
};

Bingo! Désormais, notre fenêtre ne s'affiche que lorsque le chargement de la vue Web est terminé, évitant ainsi ce scintillement visuel gênant.

Conclusion

Félicitations, vous avez construit votre premier plug-in Sketch! 1965

Si vous souhaitez installer et jouer avec Mosaic, vous pouvez télécharger le plug-in complet de GitHub. Et avant de partir, voici quelques ressources qui pourraient vous être utiles pendant le reste de votre voyage:

  • developer.sketchapp.com
    La ressource officielle concernant le développement du plug-in Sketch. Contient plusieurs guides utiles, ainsi qu'une référence d'API pour la bibliothèque JavaScript Sketch.
  • sketchplugins.com
    Une communauté fantastique et utile de développeurs de plug-in Sketch. Parfait pour obtenir des réponses à toutes vos questions brûlantes.
  • github.com/sketchplugins/plugin-directory
    Dépôt officiel et central de GitHub pour les plugins Sketch. Vous pouvez soumettre vos plugins ici et les partager avec le reste de la communauté Sketch!
 Editorial Smashing (mb, yk, il)



Source link