アニメーション効果をカスタマイズするDrawable
10167 ワード
Androidが提供するアニメーションシステムには、プロパティアニメーション(Property Animation)、パッチアニメーション(View Animation)、フレームアニメーション(Drawable Animation)がある.現在よく使われているのは属性アニメーションですが、機能が強いため、通常はビューコントロール(View)を直接属性アニメーション化することが多いですが、アニメーション効果Drawableの実現について説明します.ViewよりDrawableの方が簡単で、使いやすいです.
一.カスタムDrawable
カスタムアニメーションDrawableは、Drawableを継承し、次の4つの方法を実装し、Animatableインタフェースを実装します.
draw()メソッドは、カスタムViewと同じです.私たちはアニメーション効果を実現し、Animatableインタフェースも実現しなければなりません.その3つの方法はすべてアニメーションに関連しており、方法の意図も明らかです.円が徐々に拡散して消える効果をカスタマイズします.
mRadiusPropertyは、円を描く半径を制御するために使用され、半径の制御に加えて透明度の制御もあります.カスタムアトリビュートPropertyとPropertyValuesHolderが不明な場合は、AndroidアトリビュートアニメーションPropertyValuesHolderの使用を参照してください.
ImageViewにカスタマイズしたCircleDrawableの効果を設定します.
二.複数のアニメーションを含むDrawable
同様に、複数のアニメーションを含むカスタムDrawableを実現するにはDrawableを継承しAnimatableインタフェースを実現するとともにDrawableを実現する必要がある.Callbackインタフェース.まず見てみましょうCallbackの定義:
invalidateSelf()インタフェースは、次のように動作します.
Drawable.Callbackコールバックは、このDrawableの再描画操作を傍受し、invalidateDrawable(Drawable who)メソッドをコールバックすることができます.
次に、複数のアニメーションを持つDrawableのカスタマイズを開始し、上に書いたCircleDrawableを直接多重化し、複数のCircleDrawableアニメーションを順番に実行します.
アニメーションの開始遅延と
Drawable.Callbackコールバックは、コールバックメソッドinvalidateDrawable(Drawable who)でも現在のMultiCircleDrawableを再描画し、invalidateSelf()を呼び出します.これで複数のアニメーションDrawableの定義が完了し、使用効果を見てみましょう.
これは、カスタムDrawableの使用を簡単に紹介するだけで、より美しいアニメーション効果を自分で定義することができます.以上のソースコード:DrawableSample.
カスタムDrawableの運用はこれを参考にすることができます:360携帯電話アシスタントTabHostの波紋効果を実現します
一.カスタムDrawable
カスタムアニメーションDrawableは、Drawableを継承し、次の4つの方法を実装し、Animatableインタフェースを実装します.
public class CircleDrawable extends Drawable implements Animatable {
@Override
public void draw(Canvas canvas) {
//
}
@Override
public void setAlpha(int alpha) {
//
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
//
}
@Override
public int getOpacity() {
//
return PixelFormat.RGBA_8888;
}
@Override
public void start() {
//
}
@Override
public void stop() {
//
}
@Override
public boolean isRunning() {
//
return false;
}
}
このいくつかの方法では、Drawableの描画を主に処理します.draw()メソッドは、カスタムViewと同じです.私たちはアニメーション効果を実現し、Animatableインタフェースも実現しなければなりません.その3つの方法はすべてアニメーションに関連しており、方法の意図も明らかです.円が徐々に拡散して消える効果をカスタマイズします.
/**
* Created by long on 2016/7/2.
* Drawable
*/
public class CircleDrawable extends Drawable implements Animatable {
private Paint mPaint;
//
private ValueAnimator mValueAnimator;
//
private int mRadius;
//
private RectF mRect = new RectF();
//
private int mStartDelay;
//
Property<CircleDrawable, Integer> mRadiusProperty = new Property<CircleDrawable, Integer>(Integer.class, "radius") {
@Override
public void set(CircleDrawable object, Integer value) {
object.setRadius(value);
}
@Override
public Integer get(CircleDrawable object) {
return object.getRadius();
}
};
public int getRadius() {
return mRadius;
}
public void setRadius(int radius) {
mRadius = radius;
}
public CircleDrawable() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
}
@Override
public void draw(Canvas canvas) {
//
canvas.drawCircle(mRect.centerX(), mRect.centerY(), mRadius, mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.RGBA_8888;
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(_clipSquare(bounds));
if (isRunning()) {
stop();
}
//
int maxRadius = (int) ((mRect.right - mRect.left) / 2);
//
PropertyValuesHolder radiusHolder = PropertyValuesHolder.ofInt(mRadiusProperty, 0, maxRadius);
//
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("alpha", 255, 0);
mValueAnimator = ObjectAnimator.ofPropertyValuesHolder(this, radiusHolder, alphaHolder);
mValueAnimator.setStartDelay(mStartDelay);
mValueAnimator.setDuration(1200);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//
invalidateSelf();
}
});
//
mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
start();
}
/**
* Rect
* @param rect
* @return
*/
private Rect _clipSquare(Rect rect) {
int w = rect.width();
int h = rect.height();
int min = Math.min(w, h);
int cx = rect.centerX();
int cy = rect.centerY();
int r = min / 2;
return new Rect(
cx - r,
cy - r,
cx + r,
cy + r
);
}
/************************************************************/
@Override
public void start() {
mValueAnimator.start();
}
@Override
public void stop() {
mValueAnimator.end();
}
@Override
public boolean isRunning() {
return mValueAnimator != null && mValueAnimator.isRunning();
}
public void setAnimatorDelay(int startDelay) {
mStartDelay = startDelay;
}
}
全体の流れは比較的簡単で、コンストラクション関数でブラシを初期化し、onBoundsChange(Rect bounds)インタフェースを複写してグラフィックフレームパラメータを取得します.例えばDrawableをImageViewに設定すると、ここでImageViewのフレームサイズを取得できます.この方法では枠を正方形に切ります.円Drawableを作るからです.あとはアトリビュートアニメーションの処理です.ここでは拡散半径アトリビュートをカスタマイズします.mRadiusPropertyは、円を描く半径を制御するために使用され、半径の制御に加えて透明度の制御もあります.カスタムアトリビュートPropertyとPropertyValuesHolderが不明な場合は、AndroidアトリビュートアニメーションPropertyValuesHolderの使用を参照してください.
ImageViewにカスタマイズしたCircleDrawableの効果を設定します.
二.複数のアニメーションを含むDrawable
同様に、複数のアニメーションを含むカスタムDrawableを実現するにはDrawableを継承しAnimatableインタフェースを実現するとともにDrawableを実現する必要がある.Callbackインタフェース.まず見てみましょうCallbackの定義:
/* Drawable drawable, setCallBack(android.graphics.drawable.Drawable.Callback)
* drawable 。
*/
public static interface Callback {
/**
* drawable , drawable
* @param drawable
*/
public void invalidateDrawable(Drawable who);
/**
* drawable 。 postAtTime(Runnable, Object, long)
* 。
* @param who The drawable being scheduled.
* @param what The action to execute.
* @param when The time (in milliseconds) to run
*/
public void scheduleDrawable(Drawable who, Runnable what, long when);
/**
* scheduleDrawable(Drawable who, Runnable what, long when) 。
* removeCallbacks(Runnable,Object)
* @param who The drawable being unscheduled.
* @param what The action being unscheduled.
*/
public void unscheduleDrawable(Drawable who, Runnable what);
}
Drawableを再描画する必要がある場合に呼び出されますinvalidateSelf()インタフェースは、次のように動作します.
/**
* Use the current {@link Callback} implementation to have this Drawable
* redrawn. Does nothing if there is no Callback attached to the
* Drawable.
*
* @see Callback#invalidateDrawable
* @see #getCallback()
* @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public void invalidateSelf() {
final Callback callback = getCallback();
if (callback != null) {
callback.invalidateDrawable(this);
}
}
Drawableに設定が必要な場合Drawable.Callbackコールバックは、このDrawableの再描画操作を傍受し、invalidateDrawable(Drawable who)メソッドをコールバックすることができます.
次に、複数のアニメーションを持つDrawableのカスタマイズを開始し、上に書いたCircleDrawableを直接多重化し、複数のCircleDrawableアニメーションを順番に実行します.
/**
* Created by long on 2016/7/2.
* Circle Drawable, Drawable.Callback
*/
public class MultiCircleDrawable extends Drawable implements Animatable, Drawable.Callback {
// Drawable
private static final int EACH_CIRCLE_SPACE = 200;
// CircleDrawable
private CircleDrawable[] mCircleDrawables;
public MultiCircleDrawable() {
mCircleDrawables = new CircleDrawable[] {
new CircleDrawable(),
new CircleDrawable(),
new CircleDrawable()
};
for (int i = 0; i < mCircleDrawables.length; i++) {
//
mCircleDrawables[i].setAnimatorDelay(EACH_CIRCLE_SPACE * i);
// , CircleDrawable invalidateDrawable(Drawable who)
mCircleDrawables[i].setCallback(this);
}
}
@Override
public void draw(Canvas canvas) {
for (CircleDrawable drawable : mCircleDrawables) {
// CircleDrawable
int count = canvas.save();
drawable.draw(canvas);
canvas.restoreToCount(count);
}
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.RGBA_8888;
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
for (CircleDrawable drawable : mCircleDrawables) {
drawable.onBoundsChange(bounds);
}
}
/************************************************************/
@Override
public void start() {
for (CircleDrawable drawable : mCircleDrawables) {
drawable.start();
}
}
@Override
public void stop() {
for (CircleDrawable drawable : mCircleDrawables) {
drawable.stop();
}
}
@Override
public boolean isRunning() {
for (CircleDrawable drawable : mCircleDrawables) {
if (drawable.isRunning()) {
return true;
}
}
return false;
}
@Override
public void invalidateDrawable(Drawable who) {
// , Drawable Drawable, Callback
invalidateSelf();
}
@Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
}
@Override
public void unscheduleDrawable(Drawable who, Runnable what) {
}
}
には、3つのCircleDrawableが多重化され、設定されていることがわかります.アニメーションの開始遅延と
Drawable.Callbackコールバックは、コールバックメソッドinvalidateDrawable(Drawable who)でも現在のMultiCircleDrawableを再描画し、invalidateSelf()を呼び出します.これで複数のアニメーションDrawableの定義が完了し、使用効果を見てみましょう.
これは、カスタムDrawableの使用を簡単に紹介するだけで、より美しいアニメーション効果を自分で定義することができます.以上のソースコード:DrawableSample.
カスタムDrawableの運用はこれを参考にすることができます:360携帯電話アシスタントTabHostの波紋効果を実現します