Explication détaillée de l'API Canvas (partie 1)


Introduction à cette section :

Nous avons passé 13 sections à expliquer en détail la plupart des API couramment utilisées de la classe Paint dans Android. Commençons par cette section. Quelques API courantes de Canvas (planche à dessin), nous les avons répertoriées dans

  • 8.3.1 Explication détaillée de trois classes d'outils de dessin
  • Certaines des méthodes sont répartis dans les catégories suivantes :
    • Famille de méthodes drawXxx  : Dessinez une image dans la zone de dessin actuelle avec une certaine valeur de coordonnées, et les calques seront superposés. Autrement dit, la couche peinte plus tard recouvrira la couche peinte précédemment.
    • Famille de méthodes clipXXX : Recadrer (découper) une nouvelle zone de dessin dans la zone de dessin actuelle, ceci La zone de dessin est la zone de dessin actuelle de l'objet canevas. Par exemple : clipRect(new Rect()), Ensuite, la zone rectangulaire est la zone de dessin actuelle de Canvas
    • famille de méthodes getXxx  : obtenez certaines valeurs liées à Canvas, telles que la largeur, la hauteur, la densité de l'écran, etc.
    • save(), restore(), saveLayer(), restoreToCount(), etc. Enregistrez et restaurer les calques Les méthodes de
    • traduire(traduction), échelle(zoom), rotation(rotation), inclinaison(tilt )

    Bien sûr, il existe d'autres méthodes dispersées. Eh bien, à partir de cette section, je vais choisir quelques API intéressantes à apprendre~

    Et cette section vous donnera quoi. il apporte est traduction (traduction), échelle (zoom), rotation (rotation), inclinaison (inclinaison) Et des explications détaillées sur save() et restore() !

    Documentation officielle de l'API : Canvas

    De plus, il faut d'abord clarifier les directions de l'axe X et de l'axe Y dans Canvas :

    1.png

1.translate(translate)

Méthode : translate(float dx, float dy)

Analyse : Translation, déplacez l'origine des coordonnées du canevas vers la gauche et la droite par x et de haut en bas par y. La position par défaut du canevas est (0, 0)

Paramètres  : dx est la distance de déplacement dans le sens horizontal, dy est la distance de déplacement dans le sens vertical

Exemple d'utilisation :

for(int i=0; i < 5; i++) {
    canvas.drawCircle(50, 50, 50, mPaint);
    canvas.translate(100, 100);
}
Effet de fonctionnement :

2.png


2.rotate(rotate)

Méthode  :rotation(degrés flottants) / rotation(degrés flottants, float px, float py)

Analyse : rotation des degrés autour l'origine des coordonnées, la valeur est positive dans le sens des aiguilles d'une montre

Paramètres : les degrés sont l'angle de rotation, px et py sont les coordonnées du point central de la rotation spécifiée (px, py)

Exemple d'utilisation :

Rect rect = new Rect(50,0,150,50);
canvas.translate(200, 200);
for(int i = 0; i < 36;i++){
    canvas.rotate(10);
    canvas.drawRect(rect, mPaint);
}

Effet de course :

3.png

Code Analyse  :

Ici, nous appelons d'abord translation(200, 200) pour déplacer l'origine des coordonnées du canevas vers (200, 200), puis dessinons, donc nous Le résultat du dessin peut être entièrement affiché sur la toile. Si nous définissons (10 200 200) pour la rotation, cela ressemblera à ceci. Résultat :

4.png

Vous avez des questions, non ? Cela implique la notion de plusieurs couches de Canvas, dont je parlerai plus tard~


3 .scale( Scale)

méthode : scale(float sx, float sy) / scale(float sx, float sy , float px , float py)

Analyse : Mettre à l'échelle le canevas

Paramètres : sx est le rapport de mise à l'échelle horizontale, sy est la mise à l'échelle verticale Je ne connais pas non plus le rapport, px et py Décimal signifie réduction, Entier signifie élargissement

Exemple d'utilisation :

canvas.drawBitmap(bmp,0,0,mPaint);
canvas.scale(0.8f, 0.8f);
canvas.drawBitmap(bmp, 0, 0, mPaint);
canvas.scale(0.8f, 0.8f);
canvas.drawBitmap(bmp,0,0,mPaint);

Effet de fonctionnement :

5.png


4.skew(skew)

méthode skew(float sx, float sy)

Analyse : skew, peut aussi se traduire par biseau, twist

Paramètres  : sx est l'angle d'inclinaison correspondant dans la direction de l'axe x, sy est l'angle d'inclinaison correspondant dans la direction de l'axe y, les deux valeurs sont des valeurs tan ! Ce sont toutes des valeurs de bronzage ! Ce sont toutes des valeurs de bronzage ! Par exemple, si vous souhaitez incliner de 60 degrés dans la direction de l’axe x, alors la valeur décimale correspond à : tan 60 = racine carrée de 3 = 1,732 !

Exemple d'utilisation :

canvas.drawBitmap(bmp,0,0,mPaint);
canvas.translate(200, 200);
canvas.skew(0.2f,-0.8f);
canvas.drawBitmap(bmp,0,0,mPaint);

Effet d'opération :

6.png

5. Le concept de couche Canvas et explication détaillée de save() et restaurer()

Nous aimons généralement appeler Canvas Canvas, et les enfants pensent toujours que la toile est un simple morceau de papier à dessin, alors je pense Je voudrais demander comment l'animation multicouche est réalisée à l'aide de Canvas ? Dans l’exemple de traduction ci-dessus, pourquoi ? drawCircle(50, 50, 50, mPaint); La coordonnée de référence est toujours (50,50), alors pourquoi cet effet se produit-il ? Les enfants confus ont peut-être confondu le concept d’écran avec le concept de Canvas. Restaurons-le ci-dessous. La scène de crime où le traducteur a été appelé :

7.png

Comme le montre la figure, l'origine des coordonnées du canevas se déplace de 100 sur les axes x et y à chaque fois ; Et si vous dessiniez de nouveaux graphiques à différents points ? Comment le casser, traduire (-100, -100) se traduit lentement ? Pas vraiment Confus...8.jpg

D'accord, ce n'est pas grave, nous pouvons enregistrer l'état actuel du canevas avant de procéder à la transformation de la traduction. En fait, Canvas l'est. Nous fournissons un support pour les calques, et ces calques sont gérés selon la "structure de la pile"

9.png

Lorsque nous appelons la méthode save(), enregistrera l'état actuel du canevas et ajoutera à la pile Canvas en tant que calque. De plus, ce Layer n’est pas une classe spécifique, c’est juste une chose conceptuelle !

Et lorsque nous appelons la méthode restore(), l'état précédent du Canvas sera restauré, et à ce moment la pile de calques Canvas Le calque en haut de la pile apparaîtra et le calque suivant viendra en haut de la pile. À ce moment, le canevas reviendra à l'état de canevas enregistré en haut de la pile !

Pour faire simple  : save() pousse un calque sur la pile, et restaurer() fait apparaître un calque en haut de la pile. Ce calque représente le canevas. État! C'est-à-dire que vous pouvez save() plusieurs fois ou restaurer() plusieurs fois, mais le nombre d'appels de restauration ne peut pas être supérieur à save Sinon, une erreur sera générée ! C'est ce que disent la plupart des gens sur Internet, mais aucun problème de ce type ne s'est produit lors du test réel, même si j'ai restauré Le nombre de fois est plus que sauvegardé, et il n'y a pas d'erreurs~ L'inspection visuelle indique que le système a été modifié, je le montrerai à tout le monde lors du prochain test~10.gifAllez, écris un exemple pour vérifier le fonctionnement de. enregistrez et restaurez !

Écrivez un exemple :

Exemple de code:

canvas.save();  //保存当前canvas的状态

canvas.translate(100, 100);
canvas.drawCircle(50, 50, 50, mPaint);

canvas.restore();  //恢复保存的Canvas的状态
canvas.drawCircle(50, 50, 50, mPaint);

Résultat d'exécution :

11.png

Inutile de dire que le code et les résultats ont déjà tout expliqué, rendons les choses plus compliquées et essayons Plusieurs sauvegardes() et restaurations() !

Exemple de code :

canvas.save();

canvas.translate(300, 300);
canvas.drawBitmap(bmp, 0, 0, mPaint);
canvas.save();

canvas.rotate(45);
canvas.drawBitmap(bmp, 0, 0, mPaint);
canvas.save();

canvas.rotate(45);
canvas.drawBitmap(bmp, 0, 0, mPaint);
canvas.save();

canvas.translate(0, 200);
canvas.drawBitmap(bmp, 0, 0, mPaint);

Exécuter le résultat :

12.png

Résultat Analyse  :

Traduisez d'abord (300 300) pour dessiner, puis faites pivoter de 45 degrés pour dessiner, puis faites pivoter de 45 degrés pour dessiner, puis traduisez (0,200), Pendant cette période, save() est effectué à chaque fois avant le dessin. Vous pourriez avoir une question lorsque vous voyez cela. La dernière traduction n'est pas un mouvement y de 200. Eh bien, pourquoi a-t-il tourné à gauche ? Hé, dois-je vous dire que rotate() fait pivoter tout l'axe de coordonnées ? axe de coordonnées Modifications :

13.png

Eh bien, vous comprenez rotate(), non ? C'est bon, alors essayons de restaurer~ Nous sommes devant le dessin final Ajoutez deux restaurations () !

canvas.restore();
canvas.restore();
canvas.translate(0, 200);
canvas.drawBitmap(bmp, 0, 0, mPaint);

Résultats de fonctionnement :

14.png

Ne dites rien, faites-en l'expérience vous-même, ajoutez plus de restauration()!

15.png

C'est intéressant, continuons à ajouter restore()

17.png

Eh bien, il semble qu'on ne puisse plus écrire restaurer, non parce que nous n'avons sauvegardé que quatre fois. D'après Internet, Cela signalera une erreur, est-ce vraiment le cas ? Ici, nous appelons celui fourni par Canvas pour obtenir la pile actuelle Combien y a-t-il de méthodes Layer : getSaveCount() puis avant et après save() et restaurer() ; Ajoutez un journal pour imprimer le nombre de couches dans la pile :

18.png

Le résultat est vraiment gratifiant. Après tout, la pratique apporte de vraies connaissances. modifié, ou pour d'autres raisons Ici. Il faut regarder le code source pour le savoir. En raison de contraintes de temps, on sait ici que le nombre de restaurations peut être supérieur au nombre de sauvegardes. Cependant, il est toujours recommandé de restaurer moins souvent que de sauvegarder pour éviter des problèmes inutiles~ Quant au processus d’entrée et de sortie de la pile, je n’en parlerai pas, je l’ai dessiné moi-même et c’est très simple à comprendre !


6. Explication de SaveLayer() et restaurerToCount()

En fait, ces deux méthodes sont similaires pour sauvegarder et restaurer, mais il y a des choses supplémentaires basées sur le ce dernier. Juste l’Est, Par exemple, saveLayer() a les méthodes surchargées suivantes :

19.png

Vous pouvez comprendre que la méthode save() enregistre le Canvas entier , et saveLayer() peuvent enregistrer sélectivement l'état d'une certaine zone. De plus, on voit qu'il y a : int saveFlags dans le room and board, c'est le paramètre pour changer l'objet à sauvegarder ! Les valeurs facultatives sont :

标记说明
ALL_SAVE_FLAG保存全部的状态
CLIP_SAVE_FLAG保存裁剪的某个区域的状态
CLIP_TO_LAYER_SAVE_FLAG保存预先设置的范围里的状态
FULL_COLOR_LAYER_SAVE_FLAG保存彩色涂层
HAS_ALPHA_LAYER_SAVE_FLAG不透明图层保存
MATRIX_SAVE_FLAGMatrix信息(translate,rotate,scale,skew)的状态保存

PS : Il y a quelque chose qui ne va pas avec l'explication ci-dessus. Le niveau d'anglais de l'auteur est faible et je me trompe peut-être. Si vous savez quelque chose, assurez-vous de me corriger ~

.

Ici, nous écrivons un exemple pour vérifier Suivant : Nous choisissons le mode CLIP_TO_LAYER_SAVE_FLAG pour écrire un exemple

Code d'implémentation:

RectF bounds = new RectF(0, 0, 400, 400);
canvas.saveLayer(bounds, mPaint, Canvas.CLIP_TO_LAYER_SAVE_FLAG);
canvas.drawColor(getResources().getColor(R.color.moss_tide));
canvas.drawBitmap(bmp, 200, 200, mPaint);
canvas.restoreToCount(1);
canvas.drawBitmap(bmp, 300, 200, mPaint);

Résultat d'exécution :

20.png

Étudions en détail saveLayer() car il sera utilisé plus tard~ Voici une idée approximative~

Ensuite allez dans ce restoreToCount(int), c'est plus simple, transmettez simplement le nombre de calques sur lesquels vous souhaitez restaurer. Accédez directement au calque correspondant et en même temps expulsez tous les calques au-dessus du calque de la pile, de sorte que le calque Devenez le sommet de la pile ~ ! C'est beaucoup plus pratique et plus rapide que d'écrire plusieurs restaurations()~


7. Téléchargez l'exemple de code dans cette section :

Eh bien, le code est écrit pour les tests, donc il n'y a pas besoin Cela ne veut pas dire grand-chose, mais peut-être que les lecteurs le veulent toujours, alors postez simplement le lien !

Téléchargement du code : CanvasDemo.zipC'est peut-être la photo que vous voulez ! Haha~

21.jpg


Résumé de cette section :

Cette section m'a pris quelques jours à écrire car l'auteur n'était pas sûr de au début. Le concept de cette couche Canvas n'est pas non plus très clair. Après avoir terminé mon travail cet après-midi, j'ai réfléchi à mes pensées, j'ai fait des heures supplémentaires le soir et j'ai finalement écrit cet article, je pense qu'il sera utile. Tout le monde comprend Canvas plus clairement, et vous ne serez pas confus lorsque les contrôles personnalisés avancés ~ Héhé, c'est tout pour cette section. S'il y a des erreurs, merci de les signaler, merci beaucoup~21.gif