アニメーションのようにバースト

一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して13日目です。クリックしてイベントの詳細をご覧ください

序文

以前、バースト効果のあるようなアプリを偶然見たのですが、ちょっとおもしろいと思ったので、少し復元してみました。効果は以下のとおりです。

GIF.gif

カプセル化された粒子

アニメーション効果から、アニメーションが開始されると、すべての方向から散乱された粒子のグループがあり、その後徐々に消えていくことがわかります。したがって、次のプロパティを含む粒子クラスを定義できます。

public class Particle {
    public float x, y;
    public float startXV;
    public float startYV;
    public float angle;
    public float alpha;
    public Bitmap bitmap;
    public int width, height;
}
复制代码
  • x、yはパーティクルの位置情報です
  • startXV、startYVはXおよびY方向の速度です
  • 角度は発散の角度です
  • アルファは粒子の透明度です
  • ビットマップ、幅、高さは粒子画像情報です

いくつかのデフォルト値を指定して、コンストラクターでこの情報を初期化します

public Particle(Bitmap originalBitmap) {
    alpha = 1;
    float scale = (float) Math.random() * 0.3f + 0.7f;
    width = (int) (originalBitmap.getWidth() * scale);
    height = (int) (originalBitmap.getHeight() * scale);
    bitmap = Bitmap.createScaledBitmap(originalBitmap, width, height, true);

    startXV = new Random().nextInt(150) * (new Random().nextBoolean() ? 1 : -1);
    startYV = new Random().nextInt(170) * (new Random().nextBoolean() ? 1 : -1);
    int i = new Random().nextInt(360);
    angle = (float) (i * Math.PI / 180);

    float rotate = (float) Math.random() * 180 - 90;
    Matrix matrix = new Matrix();
    matrix.setRotate(rotate);
    bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
    originalBitmap.recycle();
}
复制代码

エフェクトアニメーションをよく見ると、同じ画像の回転角が毎回異なることがわかります。そのため、ビットマップを作成するときに、画像をランダムに回転させます。

粒子を描く

パーティクルを取得したら、それをビューに描画し、ParticleViewを定義し、onDraw()メソッドをオーバーライドして、描画を完了する必要があります。

public class ParticleView extends View {
    Paint paint;
    List<Particle> particles = new ArrayList<>();
    //.....省略构造函数
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (Particle particle : particles) {
            paint.setAlpha((int) (particle.alpha * 255));
            canvas.drawBitmap(particle.bitmap, particle.x - particle.width / 2, particle.y - particle.height / 2, paint);
        }
    }
    public void setParticles(List<Particle> particles) {
        this.particles = particles;
    }
}
复制代码

粒子を管理する

描画するとき、パーティクルを移動させるには、パーティクルのx値とy値を絶えず変更する必要があることがわかりました。そのため、ValueAnimatorが必要であり、アニメーションの実行を監視してパーティクルを継続的に描画します。

private void startAnimator(View emiter) {
    ValueAnimator valueAnimator = ObjectAnimator.ofInt(0, 1).setDuration(1000);
    valueAnimator.addUpdateListener(animation -> {
        for (Particle particle : particles) {
            particle.alpha = 1 - animation.getAnimatedFraction();
            float time = animation.getAnimatedFraction();
            time *= 10;
            particle.x = startX - (float) (particle.startXV * time * Math.cos(particle.angle));
            particle.y = startY - (float) (particle.startYV * time * Math.sin(particle.angle) - 9.8 * time * time / 2);
        }
        particleView.invalidate();
    });
    valueAnimator.start();
}
复制代码

いいねボタンはRecyclerViewのアイテムによく表示され、いいねアニメーションは全画面表示であるため、アイテムのxmlファイルに書き込むことはできません。侵入をゼロにして、元のロジックを変更せずに追加する必要があります。アニメーション効果。

activity.findViewById(android.R.id.content)取得FrameLayoutして、子ビューを追加できます

public ParticleManager(Activity activity, int[] drawableIds) {
    particles = new ArrayList<>();
    for (int drawableId : drawableIds) {
        particles.add(new Particle(BitmapFactory.decodeResource(activity.getResources(), drawableId)));
    }
    topView = activity.findViewById(android.R.id.content);
    topView.getLocationInWindow(parentLocation);
}
复制代码

まず、現在の必要な画像リソースをコンストラクターに渡しActivity、次に画像リソースをオブジェクトに解析してParticle保存し、位置情報particlesを取得します。topView

次に、アニメーションがどこから始まるかを知り、ビューをアンカーとして渡す必要があります

public void start(View emiter) {
    int[] location = new int[2];
    emiter.getLocationInWindow(location);
    startX = location[0] + emiter.getWidth() / 2 - parentLocation[0];
    startY = location[1] - parentLocation[1];
    particleView = new ParticleView(topView.getContext());
    topView.addView(particleView);
    particleView.setParticles(particles);
    startAnimator(emiter);
}
复制代码

1つ渡すことでemiter、開始位置情報が計算され、particleViewのパーティクル情報が初期化され、最後にアニメーションが開始されます。

使用する

val ids = ArrayList<Int>()
for (index in 1..18) {
    val id = resources.getIdentifier("img_like_$index", "mipmap", packageName);
    ids.add(id)
}
collectImage.setOnClickListener {
    ParticleManager(this, ids.toIntArray())
        .start(collectImage)
}
复制代码

実行後、基本的にレンダリングと同じであることがわかりますが、実際には潜在的な問題があります。topViewにビューを追加しただけですが、削除しませんでした。インターフェイスには表示されませんが、パーティクルの透明度が最後に0であるという理由だけで、パーティクルの透明度の最小値を0.1に設定した後、アニメーションの終了後にパーティクルが消えず、ますます蓄積することがわかります。ビューを削除する必要があります。

valueAnimator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationStart(Animator animation, boolean isReverse) {
    }
    @Override
    public void onAnimationEnd(Animator animation) {
        topView.removeView(particleView);
        topView.postInvalidate();
    }
    @Override
    public void onAnimationCancel(Animator animation) {
        topView.removeView(particleView);
        topView.postInvalidate();
    }
});
复制代码

削除のタイミングはアニメーションが完了したときなので、引き続き前のvalueAnimatorを使用して、その完了イベントを監視し、ビューを削除します。もちろん、アニメーションがキャンセルされた場合は、アニメーションも削除する必要があります。

おすすめ

転載: juejin.im/post/7086471790502871054