Desenvolvimento HarmonyOS 5.0: Framework ArkUI - Animações de Propriedades Personalizadas

Animações de propriedades são efeitos visuais contínuos que ocorrem na interafce do usuário quando os valores dos parâmetros de propriedades animáveis mudam. Quando os valores mudam continuamente e são aplicados a interfaces de propriedades que podem causar mudanças na UI, é possível implementar animações de propriedades.

O ArkUI fornece o decorator @AnimatableExtend para definir interfaces de propriedades animáveis personalizadas. Como o tipo de dados dos parâmetros deve ter uma certa continuidade, os tipos de parâmetros suportados para interfaces de propriedades animáveis personalizadas são apenas o tipo number e tipos personalizados que implementam a interface AnimatableArithmetic<T>. Através de interfaces de propriedades animáveis personalizadas e tipos de dados animáveis, ao usar animateTo ou animation, modificando os valores de interfaces de propriedades não animáveis através de funções de callback por quadro, é possível fazer com que interfaces de propriedades não animáveis alcancem efeitos de animação. Também é possível modificar os valores de propriedades animáveis por quadro através de funções de callback por quadro para alcançar efeitos de layout quadro a quadro.

Usando tipo de dados number e decorator @AnimatableExtend para alterar a largura do componente Text e alcançar efeito de layout quadro a quadro

// Primeiro passo: usar o decorator @AnimatableExtend para definir interface de propriedade animável personalizada
@AnimatableExtend(Text)
function larguraAnimavel(largura: number) {
  .width(largura)
}

@Entry
@Component
struct ExemploPropriedadeAnimavel {
  @State larguraTexto: number = 80;

  build() {
    Column() {
      Text("PropriedadeAnimavel")
        .larguraAnimavel(this.larguraTexto)
        .animation({ duration: 2000, curve: Curve.Ease })
      Button("Reproduzir")
        .onClick(() => {
          this.larguraTexto = this.larguraTexto == 80 ? 160 : 80;
        })
    }.width("100%")
    .padding(10)
  }
}

Usando tipo de dados personalizado e decoratro @AnimatableExtend para alterar forma图形

declare type Coordenada = number[];

// Definir tipo de parâmetro para interface de propriedade animável, implementando funções de adição, subtração, multiplicação e comparação de igualdade da interface AnimatableArithmetic<t>
class Ponto extends Array<number> {
  constructor(valor: Coordenada) {
    super(valor[0], valor[1])
  }

  adicionar(direita: Ponto): Ponto {
    let resultado: Coordenada = new Array<number>() as Coordenada;
    for (let i = 0; i < 2; i++) {
      resultado.push(direita[i] + this[i])
    }
    return new Ponto(resultado);
  }

  subtrair(direita: Ponto): Ponto {
    let resultado: Coordenada = new Array<number>() as Coordenada;
    for (let i = 0; i < 2; i++) {
      resultado.push(this[i] - direita[i]);
    }
    return new Ponto(resultado);
  }

  multiplicar(escala: number): Ponto {
    let resultado: Coordenada = new Array<number>() as Coordenada;
    for (let i = 0; i < 2; i++) {
      resultado.push(this[i] * escala)
    }
    return new Ponto(resultado);
  }
}

// Definir tipo de parâmetro para interface de propriedade animável, implementando as funções da interface AnimatableArithmetic<t>
// O template T suporta tipos aninhados que implementam AnimatableArithmetic<t>
class VetorPontos extends Array<ponto> implements AnimatableArithmetic<array>> {
  constructor(valorInicial: Array<coordenada>) {
    super();
    if (valorInicial.length) {
      valorInicial.forEach((p: Coordenada) => this.push(new Ponto(p)))
    }
  }

  // implementar a interface IAnimatableArithmetic
  mais(direita: VetorPontos): VetorPontos {
    let resultado = new VetorPontos([]);
    const tamanho = Math.min(this.length, direita.length)
    for (let i = 0; i < tamanho; i++) {
      resultado.push(this[i].adicionar(direita[i]))
    }
    return resultado;
  }

  menos(direita: VetorPontos): VetorPontos {
    let resultado = new VetorPontos([]);
    const tamanho = Math.min(this.length, direita.length)
    for (let i = 0; i < tamanho; i++) {
      resultado.push(this[i].subtrair(direita[i]))
    }
    return resultado;
  }

  multiplicar(escala: number): VetorPontos {
    let resultado = new VetorPontos([]);
    for (let i = 0; i < this.length; i++) {
      resultado.push(this[i].multiplicar(escala))
    }
    return resultado;
  }

  ehIgual(direita: VetorPontos): boolean {
    if (this.length !== direita.length) {
      return false;
    }
    for (let indice = 0, tamanho = this.length; indice < tamanho; ++indice) {
      if (this[indice][0] !== direita[indice][0] || this[indice][1] !== direita[indice][1]) {
        return false;
      }
    }
    return true;
  }
}

// Interface de propriedade animável personalizada
@AnimatableExtend(Polyline)
function pontosAnimaveis(pontos: VetorPontos) {
  .points(pontos)
}

@Entry
@Component
struct FormaAnimada {
  pontoInicialX: number = 75;
  pontoInicialY: number = 25;
  larguraQuadrado: number = 150;
  translacaoFinalX: number = 50;
  translacaoFinalY: number = 50;
  @State vetorPontos1: VetorPontos = new VetorPontos([
    [this.pontoInicialX, this.pontoInicialY],
    [this.pontoInicialX + this.larguraQuadrado, this.pontoInicialY],
    [this.pontoInicialX + this.larguraQuadrado, this.pontoInicialY + this.larguraQuadrado],
    [this.pontoInicialX, this.pontoInicialY + this.larguraQuadrado]
  ]);
  @State vetorPontos2: VetorPontos = new VetorPontos([
    [this.pontoInicialX + this.translacaoFinalX, this.pontoInicialY + this.pontoInicialY],
    [this.pontoInicialX + this.larguraQuadrado + this.translacaoFinalX, this.pontoInicialY + this.pontoInicialY],
    [this.pontoInicialX + this.larguraQuadrado, this.pontoInicialY + this.larguraQuadrado],
    [this.pontoInicialX, this.pontoInicialY + this.larguraQuadrado]
  ]);
  @State cor: Color = Color.Green;
  @State tamanhoFonte: number = 20.0;
  @State vetorLinha1: VetorPontos = this.vetorPontos1;
  @State vetorLinha2: VetorPontos = this.vetorPontos2;

  build() {
    Row() {
      Polyline()
        .width(300)
        .height(200)
        .backgroundColor("#0C000000")
        .fill('#317AF7')
        .pontosAnimaveis(this.vetorLinha1)
        .animation({ duration: 2000, delay: 0, curve: Curve.Ease })
        .onClick(() => {

          if (this.vetorLinha1.ehIgual(this.vetorPontos1)) {
            this.vetorLinha1 = this.vetorPontos2;
          } else {
            this.vetorLinha1 = this.vetorPontos1;
          }
        })
    }
    .width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}
</coordenada></array></ponto></t></t></number></number></number></number></t>

Tags: HarmonyOS ArkUI animations custom properties @AnimatableExtend

Publicado em 6-22 17:00