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

Implementation de l'effet Xun Yi Xun en Android avec View personnalisé

Cet article présente la création d'une vue personnalisée en配合属性动画来实现以下效果

L'idée de mise en œuvre est assez simple :

  • Dessiner un cercle semi-transparent
  • Mettre en œuvre deux effets d'animation, l'un pour l'expansion au clic et l'autre pour le réenroulement sans clic
  • Combiner les deux étapes précédentes en utilisant un thread

Regardons d'abord la partie de dessin de cercle semi-transparent

public class ClickCircleView extends View {
 private Bitmap bitmap;
 private Paint paint;
 private Canvas canvas;
 private boolean isSpreadFlag = false;//Marquer si l'émission est terminée
 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); // Set the width and height of the 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);
 }
}

As can be seen, the relevant properties are all set on the pen, then directly call the canvas's drawCircle() method to draw a semi-transparent circle, and finally call the invalidate() method to refresh the View
It is necessary to override the parent class's onDraw() method, otherwise the custom View cannot take effect
We set a flag isSpreadFlag, which is used to mark whether the expansion animation is completed

Then we will implement two animation effects

animation of expansion when clicked

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

It's very simple, just change the scale value to increase to1.8times

animation of expansion and recovery when not clicked

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

Similaire à l'animation précédente, le paramètre startOffset peut être utilisé pour contrôler l'ordre d'exécution de l'Animation, par exemple Android:startOffset=""10"00" signifie configurer le délai d'animation de cette propriété1Seconde d'exécution

Ensuite, c'est la partie où l'animation et la logique sont exécutées par un thread

Partie animée au moment du clic non détecté

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();
    // Charger l'animation
    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();//Exécution en boucle de l'animation
      }
     }
    });
    anim.setTarget(clickCircleView);
    anim.start();
   }
  });

Après avoir initialisé clickCircleView, ajoutez ce view au layout parent, puis chargez l'animation et configurez l'exécution en boucle, enfin utilisez postInvalidate() pour actualiser le view en mode sous-thread

Partie animée au moment du clic

mXiuyixiuButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    clickCircleView.setVisibility(View.GONE);//Dessiner un cercle, cacher le View d'animation en boucle
    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);//Marquer que l'animation est terminée
     }
    });
    spreadAnim.setTarget(item);
    spreadAnim.start();
    clickCircleViewList.add(item);
    mXiuyixiuLayout.addView(item);
    mXiuyixiuLayout.invalidate();
    handler.post(circleViewRunnable);
   }
  });


Masquer l'animation non cliquable, initialise bien ClickCircleView puis ajoute ce view à la liste et à la mise en page parente, puis charge l'animation et ajoute le marqueur isSpreadFlag à la fin de l'animation, puis appelle la méthode invalidate() pour actualiser le view et démarrer le thread

Partie thread

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);
  }
 };

Parcourir la liste, supprimer les vues marquées par isSpreadFlag de la liste et du layout parent, puis actualiser la vue, enfin, si la liste est vide, afficher l'animation lors du clic

N'oubliez pas de supprimer le thread dans onDestroy()

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

L'utilisation de View personnalisé avec l'animation des propriétés pour réaliser cet effet a une forte cohérence, mais par rapport à l'utilisation complète de View personnalisé, cette méthode est plus fluide, la plupart des codes de cette méthode sont tirés des blogs d'autres personnes, mais si vous ne résumez pas simplement pour utiliser, cela ne deviendra pas votre propre connaissance, donc j'ai écrit ce blog.

Référence : plusieurs idées et méthodes pour réaliser le fonctionnalité 'Xiu Xiu' d'Alipay en Android

C'est tout le contenu de cet article, j'espère que cela aidera à votre apprentissage, et j'espère que vous soutiendrez également le tutoriel d'alarme.

Déclaration : le contenu de cet article est extrait du réseau, la propriété intellectuelle appartient à l'auteur original, le contenu est apporté par les utilisateurs d'Internet et téléchargé spontanément, ce site Web ne détient pas de propriété, n'a pas été traité par l'éditeur humain et n'assume aucune responsabilité juridique. Si vous trouvez du contenu suspect de violation de copyright, veuillez envoyer un e-mail à : notice#w3Déclaration : le contenu de cet article est extrait du réseau, la propriété intellectuelle appartient à l'auteur original, le contenu est apporté par les utilisateurs d'Internet et téléchargé spontanément, ce site Web ne détient pas de propriété, n'a pas été traité par l'éditeur humain et n'assume aucune responsabilité juridique. Si vous trouvez du contenu suspect de violation de copyright, veuillez envoyer un e-mail à : notice#w

Vous pourriez aussi aimer