L'effet dynamique de la convergence des mots en mots est éblouissant

Je participe au recrutement du programme de signature de créateurs de la communauté technologique Nuggets, cliquez sur le lien pour vous inscrire et soumettre .

avant-propos

Lorsque j'ai introduit fl_chart pour dessiner un graphique, j'ai vu que le plug-in avait les effets dynamiques suivants, et les points dispersés aléatoires ont finalement été combinés dans le Flutter Logo, ce qui est plutôt cool. Dans cet article, nous verrons comment obtenir un effet similaire.

logo animation.gif

treillis

Avant d'expliquer l'implémentation du code, vulgarisons d'abord une connaissance, c'est-à-dire le treillis. La matrice de points est très courante dans la vie quotidienne, comme l'écran publicitaire, l'affichage du système de stationnement, appelé affichage LED dans l'industrie.

image.png

L'affichage LED est en fait un panneau d'affichage composé de nombreuses lumières LED, puis l'affichage de texte et de graphiques peut être réalisé en allumant certaines lumières et en éteignant certaines lumières. Lorsque le pas de point de l'écran LED est suffisamment petit et que les couleurs sont suffisamment riches, il constitue en fait notre affichage quotidien.Par exemple, le principe de l'écran OLED est similaire. Le même principe est utilisé dans le dortoir universitaire précédemment signalé en contrôlant l'allumage et l'extinction des lumières de chaque pièce.

image.png

Voyons maintenant comment la LED affiche le texte. Par exemple, nous voulons afficher le caractère "Île" du code fermier sur l'île. Sur une matrice de points 16x16, le résultat suivant est obtenu en arrangeant (la disposition de différentes polices seront quelque peu différentes) différence).

Parce que chaque ligne est de 16 points, nous pouvons correspondre à des nombres binaires de 16 bits, marquer le noir comme 1 et marquer le gris comme 0, et chaque ligne peut obtenir un nombre binaire. Par exemple, la 8e colonne de la première ligne ci-dessus est 1 et les autres sont 0. Le nombre binaire correspondant est 0000000100000000 et le nombre hexadécimal correspondant est 0x0100. Les autres lignes sont également calculées de cette manière, et le dernier mot "île" correspond à 16 nombres hexadécimaux, comme indiqué ci-dessous.

 [
   0x0100, 0x0200, 0x1FF0, 0x1010, 
   0x1210, 0x1150, 0x1020, 0x1000,
   0x1FFC, 0x0204, 0x2224, 0x2224,
   0x3FE4, 0x0004, 0x0028, 0x0010
 ];
复制代码

Avec cette base, nous pouvons utiliser Flutter pour dessiner des graphiques bitmap.

graphiques matriciels

Tout d'abord, on dessine un "panneau LED", qui consiste à dessiner une matrice composée de plusieurs points. C'est relativement simple, garder le même espacement, et tracer le même cercle ligne par ligne. Par exemple, on dessine une matrice de points 16x16 pour mettre en œuvre le code Comme suit.

var paint = Paint()..color = Colors.grey;
final dotCount = 16;
final fontSize = 100.0;
var radius = fontSize / dotCount;
var startPos =
    Offset(size.width / 2 - fontSize, size.height / 2 - 2 * fontSize);
for (int i = 0; i < dotCount; ++i) {
  var position = startPos + Offset(0.0, radius * i * 2);
  for (int j = 0; j < dotCount; ++j) {
    var dotPosition = startPos + Offset(radius * 2 * j, position.dy);
    canvas.drawCircle(dotPosition, radius, paint);
  }
}
复制代码

L'effet dessiné est le suivant :

image.png

接下来是点亮对应的位置来绘制文字了。上面我们讲过了,每一行是一个16进制数,那么我们只需要判断每一行的16进制数的第几个 bit是1就可以了,如果是1就点亮,否则不点亮。点亮的效果用不同的颜色就可以了。 怎么判断16进制数的第几个 bit 是不是1呢,这个就要用到位运算技巧了。实际上,我们可以用一个第 N 个 bit 是1,其他 bit 都是0的数与要判断的数进行“位与”运算,如果结果不为0,说明要判断的数的第 N 个 bit 是1,否则就是0。听着有点绕,看个例子,我们以0x0100为例,按从第0位到第15位逐个判断第0位和第15位是不是1,代码如下:

for (i = 0 ; i < 16; ++i) {
  if ((0x0100 & (1 << i)) > 0) {
    // 第 i 位为1
  }
}
复制代码

这里有两个位操作,1 << i是将1左移 i 位,为什么是这样呢,因为这样可以构成0x0001,0x0002,0x0004,...,0x8000等数字,这些数字依次从第0位,第1位,第2位,...,第15位为1,其他位都是0。然后我们用这样的数与另外一个数做位与运算时,就可以依次判断这个数的第0位,第1位,第2位,...,第15位是否为1了,下面是一个计算示例,第11位为1,其他位都是0,从而可以 判断另一个数的第11位是不是0。

ET au niveau du bit

通过这样的逻辑我们就可以判断一行的 LED 中第几列应该点亮,然后实现文字的“显示”了,实现代码如下。wordHex是对应字的16个16进制数的数组。dotCount的值是16,用于控制绘制16x16大小的点阵。每隔一行我们向下移动一段直径距离,每隔一列,我们向右移动一段直径距离。然后如果当前绘制位置的数值对应的 bit位为1,就用蓝色绘制,否则就用灰色绘制。这里说一下为什么左移的时候要用dotCount - j - 1,这是因为绘制是从左到右的,而16进制数的左边是高位,而数字j是从小到大递增的,因此要通过这种方式保证判断的顺序是从高位(第15位)到低位(第0位),和绘制的顺序保持一致。

 for (int i = 0; i < dotCount; ++i) {
  var position = startPos + Offset(0.0, radius * i * 2);
  for (int j = 0; j < dotCount; ++j) {
    var dotPosition = startPos + Offset(radius * 2 * j, position.dy);

    if ((wordHex[i] & ((1 << dotCount - j - 1))) != 0) {
      paint.color = Colors.blue[600]!;
      canvas.drawCircle(dotPosition, radius, paint);
    } else {
      paint.color = Colors.grey;
      canvas.drawCircle(dotPosition, radius, paint);
    }
  }
}
复制代码

绘制的结果如下所示。

image.png

由点聚集成字的动画实现

Ensuite, considérons comment obtenir un effet d'animation similaire mentionné au début. En fait, la méthode est très simple, c'est-à-dire qu'en fonction du nombre de LED que le texte doit "allumer", dessinez d'abord autant de LED dans des positions aléatoires, puis contrôlez ces LED pour se déplacer vers la position cible par animation - c'est-à-dire que le texte doit être là où dessiner. La formule de ce mouvement est la suivante, où t est la valeur d'animation, comprise entre 0 et 1.

formule mobile

Il convient de noter que des points aléatoires ne peuvent pas être générés pendant le processus de dessin, ce qui entraînera une nouvelle position aléatoire pour chaque dessin, c'est-à-dire que la position initiale changera, entraînant le fait que la formule ci-dessus ne tient pas, et le l'effet escompté ne sera pas atteint. De plus, il ne peut pas être construit dans la buildméthode , car la méthode de construction sera appelée à chaque actualisation, ce qui entraînera également le changement de la position initiale. Ainsi, la génération de positions aléatoires doit être effectuée dans la initStateméthode . Mais il y a un nouveau problème, c'est-à-dire qu'il n'y a pas de initStateméthode dans la méthode, et la contextlargeur et la hauteur de l'écran ne peuvent pas être obtenues, donc la position ne peut pas être générée directement.Il suffit de générer un 0-1coefficient aléatoire, puis de multiplier l'écran largeur et hauteur lors du dessin. La position initiale réelle est obtenue. Le code de génération du coefficient de position initial est le suivant :

@override
  void initState() {
  super.initState();
  var wordBitCount = 0;
  for (var hex in dao) {
    wordBitCount += _countBitOne(hex);
  }
  startPositions = List.generate(wordBitCount, (index) {
    return Offset(
      Random().nextDouble(),
      Random().nextDouble(),
    );
  });
  ...
}
复制代码

wordBitCountest de compter combien de bits sont à 1 dans un mot afin de connaître le nombre de "LEDs" à dessiner. Vient ensuite le code de dessin.Cette fois, nous ne dessinerons pas la lumière qui n'est pas brillante, puis la position à éclairer est calculée par la formule de calcul de position ci-dessus, qui garantit que la position aléatoire est dessinée au début.Avec le processus d'animation, déplacez-vous progressivement vers la position cible et convergez enfin vers un mot pour obtenir l'effet d'animation attendu. Le code est le suivant.

void paint(Canvas canvas, Size size) {
  final dotCount = 16;
  final fontSize = 100.0;
  var radius = fontSize / dotCount;
  var startPos =
      Offset(size.width / 2 - fontSize, size.height / 2 - fontSize);
  var paint = Paint()..color = Colors.blue[600]!;

  var paintIndex = 0;
  for (int i = 0; i < dotCount; ++i) {
    var position = startPos + Offset(0.0, radius * i * 2);
    for (int j = 0; j < dotCount; ++j) {
      // 判断第 i 行第几位不为0,不为0则绘制,否则不绘制
      if ((wordHex[i] & ((1 << dotCount - j))) != 0) {
        var startX = startPositions[paintIndex].dx * size.width;
        var startY = startPositions[paintIndex].dy * size.height;
        var endX = startPos.dx + radius * j * 2;
        var endY = position.dy;
        var animationPos = Offset(startX + (endX - startX) * animationValue,
            startY + (endY - startY) * animationValue);
        canvas.drawCircle(animationPos, radius, paint);
        paintIndex++;
      }
    }
  }
}
复制代码

Voyons l'effet, n'est-ce pas cool ? Le code source complet a été soumis à : Code source lié au dessin , le nom du fichier est : dot_font.dart.

点阵汇聚文字动画.gif

Résumer

Cet article présente le concept de matrice de points et explique comment dessiner du texte et des graphiques basés sur une matrice de points, puis dessine d'abord des points aléatoires, puis les rassemble dans des effets d'animation de texte. On peut voir que l'effet d'animation consistant à diviser le tout en zéro puis à rassembler le zéro en tout est plutôt cool. En fait, sur la base de cette approche, des effets d'animation plus intéressants peuvent être créés.

Je suppose que tu aimes

Origine juejin.im/post/7120233450627891237
conseillé
Classement