一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して13日目です。クリックしてイベントの詳細をご覧ください。
序文
以前、バースト効果のあるようなアプリを偶然見たのですが、ちょっとおもしろいと思ったので、少し復元してみました。効果は以下のとおりです。
カプセル化された粒子
アニメーション効果から、アニメーションが開始されると、すべての方向から散乱された粒子のグループがあり、その後徐々に消えていくことがわかります。したがって、次のプロパティを含む粒子クラスを定義できます。
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を使用して、その完了イベントを監視し、ビューを削除します。もちろん、アニメーションがキャンセルされた場合は、アニメーションも削除する必要があります。