O efeito dinâmico de convergir palavras em palavras é deslumbrante

Estou participando do recrutamento do programa de assinatura de criadores da Comunidade de Tecnologia Nuggets, clique no link para se cadastrar e enviar .

prefácio

Quando introduzi o fl_chart para desenhar um gráfico, vi que o plug-in tinha os seguintes efeitos dinâmicos, e os pontos dispersos aleatórios foram finalmente combinados no logotipo do Flutter, o que é bem legal. Neste artigo, discutiremos como obter um efeito semelhante.

animação do logotipo.gif

treliça

Antes de explicar a implementação do código, vamos primeiro popularizar um conhecimento, ou seja, treliça. A matriz de pontos é muito comum no dia a dia, como tela de publicidade, display de sistema de estacionamento, que é chamado de display LED na indústria.

imagem.png

O display de LED é na verdade um painel de exibição composto por muitas luzes de LED, e então a exibição de texto e gráficos pode ser realizada acendendo algumas luzes e apagando algumas luzes. Quando o dot pitch do display LED é pequeno o suficiente e as cores são ricas o suficiente, ele realmente forma nosso display diário.Por exemplo, o princípio do display OLED é similar. O mesmo princípio é usado no edifício dormitório da universidade relatado anteriormente, controlando as luzes em cada sala para ligar e desligar.

imagem.png

Agora vamos dar uma olhada em como o LED exibe o texto. Por exemplo, queremos exibir o caractere "Ilha" do agricultor de código na ilha. Em uma matriz de pontos de 16x16, o seguinte resultado é obtido organizando (o layout de diferentes fontes serão um pouco diferentes) diferença).

Como cada linha tem 16 pontos, podemos corresponder a números binários de 16 bits, marcar o preto como 1 e marcar o cinza como 0, e cada linha pode obter um número binário. Por exemplo, a 8ª coluna da primeira linha acima é 1 e as outras são 0. O número binário correspondente é 0000000100000000 e o número hexadecimal correspondente é 0x0100. As demais linhas também são calculadas dessa forma, e a palavra final "ilha" corresponde a 16 números hexadecimais, conforme mostrado abaixo.

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

Com essa base, podemos usar o Flutter para desenhar gráficos de bitmap.

gráficos de matriz de pontos

Primeiro, desenhamos um "painel de LED", que é desenhar uma matriz composta por vários pontos. Isso é relativamente simples, mantenha o mesmo espaçamento e desenhe o mesmo círculo linha por linha. Por exemplo, desenhamos uma matriz de pontos de 16x16 para implementar o código da seguinte forma.

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);
  }
}
复制代码

O efeito desenhado é o seguinte:

imagem.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。

E bit a 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);
    }
  }
}
复制代码

绘制的结果如下所示。

imagem.png

由点聚集成字的动画实现

Em seguida, vamos considerar como obter um efeito de animação semelhante ao mencionado no início. Na verdade, o método é muito simples, ou seja, de acordo com o número de LEDs que o texto deve "acende", primeiro desenhe tantos LEDs em posições aleatórias, e depois controle esses LEDs para mover para a posição alvo através de animação - ou seja, o texto deve estar onde desenhar. A fórmula para este movimento é a seguinte, onde t é o valor da animação, variando de 0-1.

fórmula móvel

Ressalta-se que pontos aleatórios não podem ser gerados durante o processo de sorteio, o que resultará em uma nova posição aleatória para cada sorteio, ou seja, a posição inicial será alterada, resultando no fato de que a fórmula acima não se mantém, e a efeito esperado não será alcançado. Além disso, ele não pode ser construído no buildmétodo , pois o método build será chamado toda vez que você atualizar, o que também fará com que a posição inicial seja alterada. Assim, a geração de posições aleatórias deve ser feita no initStatemétodo . Mas há um novo problema, ou seja, não há initStatemétodo no método, e a contextlargura e a altura da tela não podem ser obtidas, então a posição não pode ser gerada diretamente. Precisamos apenas gerar um 0-1coeficiente aleatório e depois multiplicar a tela largura e altura ao desenhar. A posição inicial real é obtida. O código de geração do coeficiente de posição inicial é o seguinte:

@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(),
    );
  });
  ...
}
复制代码

wordBitCounté contar quantos bits são 1 em uma palavra para saber o número de "LEDs" a serem desenhados. A seguir vem o código de desenho. Desta vez, não vamos desenhar a luz que não é brilhante, e então a posição a ser iluminada é calculada pela fórmula de cálculo de posição acima, que garante que a posição aleatória seja desenhada no início. processo de animação, mover-se gradualmente para a posição de destino e, finalmente, convergir em uma palavra para obter o efeito de animação esperado.O código é o seguinte.

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++;
      }
    }
  }
}
复制代码

Vamos ver o efeito, não é legal? O código-fonte completo foi enviado para: Código-fonte relacionado ao desenho , o nome do arquivo é: dot_font.dart.

点阵汇聚文字动画.gif

Resumir

Este artigo apresenta o conceito de matriz de pontos e como desenhar texto e gráficos com base em matriz de pontos e, finalmente, desenha pontos aleatórios primeiro e depois os reúne em efeitos de animação de texto. Pode-se ver que o efeito de animação de dividir o todo por zero e depois juntar o zero ao todo é bem legal. De fato, com base nessa abordagem, efeitos de animação mais interessantes podem ser criados.

おすすめ

転載: juejin.im/post/7120233450627891237
おすすめ