Android自定义属性动画

当我们对一个View进行透明度变化的动画,我们可以这样写:

ValueAnimator fadeAnimator = ObjectAnimator.ofFloat(myView, View.ALPHA, 1.0f, 0.0f);
fadeAnimator.setInterpolator(PathInterpolatorCompat.create(0.33f, 0f, 0.66f, 1f));
fadeAnimator.setDuration(1120);
final AnimatorSet alertAnimator = new AnimatorSet();
alertAnimator.playTogether(fadeAnimator);
alertAnimator.start();

查看View.java的代码,可以看到View.ALPHA的常量

public static final Property ALPHA = new FloatProperty("alpha") {
        @Override
        public void setValue(View object, float value) {
            object.setAlpha(value);
        }

        @Override
        public Float get(View object) {
            return object.getAlpha();
        }
    };

再看setAlpha()方法,如果alpha值变化了invalidate()方法刷新界面

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
        ensureTransformationInfo();
        if (mTransformationInfo.mAlpha != alpha) {
            mTransformationInfo.mAlpha = alpha;
            if (onSetAlpha((int) (alpha * 255))) {
                mPrivateFlags |= PFLAG_ALPHA_SET;
                // subclass is handling alpha - don't optimize rendering cache invalidation
                invalidateParentCaches();
                invalidate(true);
            } else {
                mPrivateFlags &= ~PFLAG_ALPHA_SET;
                invalidateViewProperty(true, false);
                mRenderNode.setAlpha(getFinalAlpha());
                notifyViewAccessibilityStateChangedIfNeeded(
                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
            }
        }
    }

再看getAlpha()方法,返回view当前的alpha

public float getAlpha() {
        return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
    }

所以一个自定义的动画,需要一个动画的属性常量,并实现setget方法,set方法需要判断当动画属性值变化的时候刷新当前View.

例如我们定义圆形波浪动画:

public final static Property RADIUS =
            new Property(Float.class, "radius") {
                @Override
                public Float get(WaveView view) {
                    return view.getRadius();
                }

                @Override
                public void set(WaveView view, Float value) {
                    view.setRadius(value);
                }
            };

public WaveView setRadius(float radius) {
        final float oldRadius = mRadius;
        if (oldRadius != radius) {
            mRadius = radius;

            invalidate(mCenterX, mCenterY, oldRadius);
            if (radius > oldRadius) {
                invalidate(mCenterX, mCenterY, radius);
            }
        }

        return this;
    }

public final float getRadius() {
        return mRadius;
    }

然后在可以Animator调用RADIUS这个属性做动画,例如:

Animator animator = ObjectAnimator.ofFloat(myView, WaveView.RADIUS, 122f, 192f);
                animator.setInterpolator(PathInterpolatorCompat.create(0.2f, 0f, 0.24f, 1f));
                animator.setDuration(1120);
                final ValueAnimator fadeAnimator = ObjectAnimator.ofFloat(myView, View.ALPHA, 1.0f, 0.0f);
                fadeAnimator.setInterpolator(PathInterpolatorCompat.create(0.33f, 0f, 0.66f, 1f));
                fadeAnimator.setDuration(1120);
                final AnimatorSet alertAnimator = new AnimatorSet();
                alertAnimator.playTogether(animator, fadeAnimator);
                alertAnimator.start();

完整的Demo例子:

package com.usetsai.myalarm;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Property;
import android.view.View;

/**
 * Created by junliang on 16-7-6.
 */
public class WaveView extends View {

    public final static Property FILL_COLOR =
            new Property(Integer.class, "fillColor") {
                @Override
                public Integer get(WaveView view) {
                    return view.getFillColor();
                }

                @Override
                public void set(WaveView view, Integer value) {
                    view.setFillColor(value);
                }
            };

    public final static Property RADIUS =
            new Property(Float.class, "radius") {
                @Override
                public Float get(WaveView view) {
                    return view.getRadius();
                }

                @Override
                public void set(WaveView view, Float value) {
                    view.setRadius(value);
                }
            };

    private final Paint mCirclePaint = new Paint();

    private float mCenterX;
    private float mCenterY;
    private float mRadius;
    private float mStrokeWidth;

    public WaveView(Context context) {
        this(context, null /* attrs */);
    }

    public WaveView(Context context, AttributeSet attrs) {
        this(context, attrs, 0 /* defStyleAttr */);
    }

    public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        final TypedArray a = context.obtainStyledAttributes(
                attrs, R.styleable.WaveView, defStyleAttr, 0 /* defStyleRes */);

        mCenterX = a.getDimension(R.styleable.WaveView_centerX, 0.0f);
        mCenterY = a.getDimension(R.styleable.WaveView_centerY, 0.0f);
        mRadius = a.getDimension(R.styleable.WaveView_radius, 0.0f);
        mStrokeWidth = a.getDimension(R.styleable.WaveView_strokeWidth, 3f);

        int fillColor = a.getColor(R.styleable.WaveView_fillColor, Color.BLUE);
        int fillEndColor = a.getColor(R.styleable.WaveView_fillEndColor, -1);
        if (fillEndColor == -1) {
            mCirclePaint.setColor(fillColor);
        } else {
            LinearGradient sweepGradient = new LinearGradient(0f,
                    a.getDimension(R.styleable.WaveView_gradientStart, 0f),
                    0f, a.getDimension(R.styleable.WaveView_gradientEnd, 0f),
                    fillColor, fillEndColor, Shader.TileMode.CLAMP);
            mCirclePaint.setShader(sweepGradient);
        }
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setStyle(Paint.Style.STROKE);
        mCirclePaint.setStrokeWidth(mStrokeWidth);
        a.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);
    }

    public final int getFillColor() {
        return mCirclePaint.getColor();
    }

    public WaveView setFillColor(int color) {
        if (mCirclePaint.getColor() != color) {
            mCirclePaint.setColor(color);

            invalidate(mCenterX, mCenterY, mRadius);
        }
        return this;
    }

    public final float getCenterX() {
        return mCenterX;
    }

    public WaveView setCenterX(float centerX) {
        final float oldCenterX = mCenterX;
        if (oldCenterX != centerX) {
            mCenterX = centerX;

            invalidate(oldCenterX, mCenterY, mRadius);
            invalidate(centerX, mCenterY, mRadius);
        }

        return this;
    }

    public final float getCenterY() {
        return mCenterY;
    }

    public WaveView setCenterY(float centerY) {
        final float oldCenterY = mCenterY;
        if (oldCenterY != centerY) {
            mCenterY = centerY;

            invalidate(mCenterX, oldCenterY, mRadius);
            invalidate(mCenterX, centerY, mRadius);
        }

        return this;
    }

    public final float getRadius() {
        return mRadius;
    }

    public WaveView setRadius(float radius) {
        final float oldRadius = mRadius;
        if (oldRadius != radius) {
            mRadius = radius;

            invalidate(mCenterX, mCenterY, oldRadius);
            if (radius > oldRadius) {
                invalidate(mCenterX, mCenterY, radius);
            }
        }

        return this;
    }

    private void invalidate(float centerX, float centerY, float radius) {
        invalidate((int) (centerX - radius - 0.5f), (int) (centerY - radius - 0.5f),
                (int) (centerX + radius + 0.5f), (int) (centerY + radius + 0.5f));
    }
}

外部调用:

Animator animator = ObjectAnimator.ofFloat(myView, WaveView.RADIUS, 122f, 192f);
                animator.setInterpolator(PathInterpolatorCompat.create(0.2f, 0f, 0.24f, 1f));
                animator.setDuration(1120);
                final ValueAnimator fadeAnimator = ObjectAnimator.ofFloat(myView, View.ALPHA, 1.0f, 0.0f);
                fadeAnimator.setInterpolator(PathInterpolatorCompat.create(0.33f, 0f, 0.66f, 1f));
                fadeAnimator.setDuration(1120);
                final AnimatorSet alertAnimator = new AnimatorSet();
                alertAnimator.playTogether(animator, fadeAnimator);
                alertAnimator.start();



你可能感兴趣的:(Android)