English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Implementação do efeito 'XuXu' do Alipay no Android Custom View

Este artigo introduz a implementação de View personalizada com animação de atributos para alcançar os seguintes efeitos

A ideia é bem simples:

  • Desenhar um círculo semi-transparente
  • Implementar dois efeitos de animação, expansão ao clicar e recolhimento ao não clicar
  • Combine os dois passos acima usando threads

Primeiro, vamos olhar para a parte de desenhar o círculo semi-transparente

public class ClickCircleView extends View {
 private Bitmap bitmap;
 private Paint paint;
 private Canvas canvas;
 private boolean isSpreadFlag = false;//marcar se foi concluído o disparo
 public boolean isSpreadFlag() {
  return isSpreadFlag;
 }
 public void setIsSpreadFlag(boolean isSpreadFlag) {
  this.isSpreadFlag = isSpreadFlag;
 }
 public ClickCircleView(Context context, int width, int height, int screenWidth, int screenHeight) {
  super(context);
  bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); // Definir as dimensões do bitmap
  canvas = new Canvas();
  canvas.setBitmap(bitmap);
  paint = new Paint(Paint.DITHER_FLAG);
  paint.setAntiAlias(true);
  paint.setColor(Color.WHITE);
  paint.setStyle(Paint.Style.FILL);
  paint.setAlpha(50);
  canvas.drawCircle(screenWidth / 2, screenHeight / 2, width / 2 + 10, paint);
  invalidate();
 }
 @Override
 protected void onDraw(Canvas canvas) {
  canvas.drawBitmap(bitmap, 0, 0, null);
 }
}

Pode ver que as propriedades relacionadas são configuradas no pincel, então chamamos diretamente o método drawCircle() do canvas para desenhar um círculo semi-transparente, e por fim chamamos o método invalidate() para atualizar o View
É obrigatório sobrescrever o método onDraw() da superclasse, senão o View personalizado não funcionará
Definimos um sinalizador de flag isSpreadFlag, cujo propósito é marcar se a animação de expansão foi concluída

Então vamos implementar os dois efeitos de animação

A animação de expansão ao clicar

<set xmlns:android="http://schemas.android.com/apk/res/android">
 <objectAnimator
  android:duration="10"00"
  android:propertyName="scaleY"
  android:valueFrom="1.0"
  android:valueTo="1.8"
  android:valueType="floatType" />
 <objectAnimator
  android:duration="10"00"
  android:propertyName="scaleX"
  android:valueFrom="1.0"
  android:valueTo="1.8"
  android:valueType="floatType" />
</set>

É muito simples, é alterar o valor de scale, aumentando até1.8vezes

A animação de expansão e recolhimento ao não clicar

<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:ordering="together">
 <objectAnimator
  android:duration="10"00"
  android:propertyName="scaleX"
  android:valueFrom="1.0"
  android:valueTo="1.2"
  android:valueType="floatType" />
 <objectAnimator
  android:duration="10"00"
  android:propertyName="scaleY"
  android:valueFrom="1.0"
  android:valueTo="1.2"
  android:valueType="floatType" />
 <objectAnimator
  android:duration="10"00"
  android:propertyName="scaleX"
  android:startOffset="10"00"
  android:valueFrom="1.2"
  android:valueTo="1.0"
  android:valueType="floatType" />
 <objectAnimator
  android:duration="10"00"
  android:propertyName="scaleY"
  android:startOffset="10"00"
  android:valueFrom="1.2"
  android:valueTo="1.0"
  android:valueType="floatType" />
</set>

e a animação anterior, o parâmetro startOffset pode ser usado para controlar a ordem de execução da Animation, por exemplo, Android:startOffset=""10"00" indica a configuração do atraso da animação dessa propriedade1segundo

Depois disso, é a vez de usar a thread para executar a animação e a lógica

parte da animação ao não clicar

mXiuyixiuButton.post(new Runnable() {
   @Override
   public void run() {
    clickCircleView = new ClickCircleView(CustomView1.this, mXiuyixiuButton.getWidth()
      , mXiuyixiuButton.getHeight(), mXiuyixiuLayout.getMeasuredWidth(),
      mXiuyixiuLayout.getMeasuredHeight());
    clickCircleView.setVisibility(View.VISIBLE);
    mXiuyixiuLayout.addView(clickCircleView);
    mXiuyixiuLayout.postInvalidate();
    // carregar a animação
    final Animator anim = AnimatorInflater.loadAnimator(CustomView1.this,
      R.animator.circle_scale_animator);
    anim.addListener(new AnimatorListenerAdapter() {
     @Override
     public void onAnimationEnd(Animator animation) {
      if (anim != null) {
       anim.start();//execução de loop da animação
      }
     }
    });
    anim.setTarget(clickCircleView);
    anim.start();
   }
  });

Depois de inicializar o clickCircleView, adicione este view ao layout pai, carregue a animação e configure para executar em loop, finalmente, use postInvalidate() para atualizar o view na thread secundária

parte da animação ao clicar

mXiuyixiuButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    clickCircleView.setVisibility(View.GONE);//Disparar o círculo, ocultar a animação de loop do View
    final ClickCircleView item = new ClickCircleView(CustomView1.this, mXiuyixiuButton.getWidth()
      , mXiuyixiuButton.getHeight(), mXiuyixiuLayout.getWidth(),
      mXiuyixiuLayout.getHeight());
    Animator spreadAnim = AnimatorInflater.loadAnimator(CustomView1.this,
      R.animator.circle_spread_animator);
    spreadAnim.addListener(new AnimatorListenerAdapter() {
     @Override
     public void onAnimationEnd(Animator animation) {
      item.setIsSpreadFlag(true);//动画执行完成,标记一下
     }
    });
    spreadAnim.setTarget(item);
    spreadAnim.start();
    clickCircleViewList.add(item);
    mXiuyixiuLayout.addView(item);
    mXiuyixiuLayout.invalidate();
    handler.post(circleViewRunnable);
   }
  });


隐藏不点击动画,初始化好ClickCircleView后将该view加入List中并添加到父布局中,然后加载动画并在动画结束时添加isSpreadFlag标记,最后调用invalidate()方法刷新view并开启线程

线程部分

private Runnable circleViewRunnable = new Runnable() {
  public void run() {
   for (int i = 0; i < clickCircleViewList.size(); i++) {
    if (clickCircleViewList.get(i).isSpreadFlag()) {
     mXiuyixiuLayout.removeView(clickCircleViewList.get(i));
     clickCircleViewList.remove(i);
     mXiuyixiuLayout.postInvalidate();
    }
   }
   if (clickCircleViewList.size() <= 0) {
    clickCircleView.setVisibility(View.VISIBLE);
   }
   handler.postDelayed(this, 100);
  }
 };

Percorrer a lista, remover o view com o marcador isSpreadFlag da lista e do layout pai e atualizar o view, por fim, se a lista estiver vazia, exibir o efeito de clique

Lembre-se de remover a thread no onDestroy() no final

@Override
 protected void onDestroy() {
  super.onDestroy();
  handler.removeCallbacks(circleViewRunnable);
 }

Usar View personalizado com animação de atributo para alcançar uma alta耦合ação, mas este método é mais fluído do que usar View personalizado completamente, a maioria do código é referenciado de blogs de outras pessoas, mas se você simplesmente usar sem resumir, não se tornará seu conhecimento, portanto, surgiu este blog.

Referência: Várias abordagens para implementar o efeito de 'Xiu Xiu' no Android

Isso é tudo o que há no artigo, esperamos que ajude no seu aprendizado e que você apoie o tutorial Gargalhadas.

Declaração: O conteúdo deste artigo é extraído da Internet, pertence ao respectivo proprietário, foi contribuído e carregado voluntariamente pelos usuários da Internet, o site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidades legais relacionadas. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie e-mail para: notice#oldtoolbag.com (ao enviar e-mail, substitua # por @ para denunciar e forneça provas relevantes. Caso seja confirmado, o site deletará imediatamente o conteúdo suspeito de violação de direitos autorais.)

Você também pode gostar