android 音乐波动动画

需求:在播放音乐的时候,随机产生不规律动画

android 音乐波动动画_第1张图片

下载地址:http://download.csdn.net/detail/qq_28195645/9700355

自定义音乐波动控件

package com.sun.audioplayingwave.sloading;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.sun.audioplayingwave.R;
import com.sun.audioplayingwave.sloading.indicator.BaseIndicatorController;
import com.sun.audioplayingwave.sloading.indicator.LineScaleIndicator;
import com.sun.audioplayingwave.sloading.indicator.LineScalePulseOutIndicator;
import com.sun.audioplayingwave.sloading.indicator.LineScalePulseOutThreeIndicator;
import com.sun.audioplayingwave.sloading.indicator.LineScalePulseOutWaveIndicator;



/**
 * Created by walkingMen on 2016/4/27.
 */
public class SLoadingIndicatorView extends View {
    private static final String TAG = SLoadingIndicatorView.class.getSimpleName();
    public static final int DefaultScale = 0;
    public static final int LineScale = 1;
    public static final int LineScalePulseOut = 2;
    public static final int LineScalePulseOutThree = 3;
    public static final int LineScalePulseOutWave = 4;

    //Sizes (with defaults in DP)
    public static final int DEFAULT_SIZE = 45;

    //attrs
    int mIndicatorId;
    int mIndicatorColor;

    Paint mPaint;
    BaseIndicatorController mIndicatorController;

    private boolean mHasAnimation;

    public SLoadingIndicatorView(Context context) {
        super(context);
        init(null, 0);
    }

    public SLoadingIndicatorView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public SLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs, defStyleAttr);
    }

    private void init(AttributeSet attrs, int defStyle) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.SLoadingIndicatorView);
        mIndicatorId = a.getInt(R.styleable.SLoadingIndicatorView_s_indicator, DefaultScale);
        mIndicatorColor = a.getColor(R.styleable.SLoadingIndicatorView_s_indicator_color, Color.WHITE);
        a.recycle();
        mPaint = new Paint();
        mPaint.setColor(mIndicatorColor);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);
        applyIndicator();
    }

    private void applyIndicator() {
        switch (mIndicatorId) {
            case DefaultScale:
                mIndicatorController = new LineScaleIndicator();
                break;
            case LineScale:
                mIndicatorController = new LineScaleIndicator();
                break;
            case LineScalePulseOut:
                mIndicatorController = new LineScalePulseOutIndicator();
                break;
            case LineScalePulseOutThree:
                mIndicatorController = new LineScalePulseOutThreeIndicator();
                bringToFront();
                break;
            case LineScalePulseOutWave:
                int[] waveFloats = new int[4];

                int w = View.MeasureSpec.makeMeasureSpec(0,
                        View.MeasureSpec.UNSPECIFIED);
                int h = View.MeasureSpec.makeMeasureSpec(0,
                        View.MeasureSpec.UNSPECIFIED);
                this.measure(w, h);
                int height = this.getMeasuredHeight();
                for (int i = 0; i < 4; i++) {
                    int intRandom = (int) (1 + Math.random() * (4 - 1 + 1));
                    int v = intRandom * 100;
                    waveFloats[i] = v;
                    Log.i(TAG, "applyIndicator: " + waveFloats[i]);
                }
                mIndicatorController = new LineScalePulseOutWaveIndicator(waveFloats);
                bringToFront();
                break;
        }
        mIndicatorController.setTarget(this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = measureDimension(dp2px(DEFAULT_SIZE), widthMeasureSpec);
        int height = measureDimension(dp2px(DEFAULT_SIZE), heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

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

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (!mHasAnimation) {
            mHasAnimation = true;
            applyAnimation();
        }
    }

    @Override
    public void setVisibility(int v) {
        if (getVisibility() != v) {
            super.setVisibility(v);
            if (v == GONE || v == INVISIBLE) {
                mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.END);
            } else {
                mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
            }
        }
    }

    /**
     * onAttachedToWindow是在第一次onDraw前调用的。也就是我们写的View在没有绘制出来时调用的,但只会调用一次。
     * onDetachedFromWindow相反
     */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mHasAnimation) {
            mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
        }
    }

    /**
     * This is called when the view is detached from a window. At this point it no longer has a surface for drawing.
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.CANCEL);
    }

    void drawIndicator(Canvas canvas) {
        mIndicatorController.draw(canvas, mPaint);
    }

    private int measureDimension(int defaultSize, int measureSpec) {
        int result = defaultSize;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(defaultSize, specSize);
        } else {
            result = defaultSize;
        }
        return result;
    }

    void applyAnimation() {
        mIndicatorController.initAnimation();
    }

    private int dp2px(int dpValue) {
        return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
    }
}

自定义插值器抽象类

package com.sun.audioplayingwave.sloading.indicator;


import android.animation.Animator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;

import java.lang.ref.WeakReference;
import java.util.List;

/**
 * Created by walkingMen on 2016/4/27.
 */

public abstract class BaseIndicatorController {


    private WeakReference mTarget;

    private List mAnimators;


    public void setTarget(View target) {
        this.mTarget = new WeakReference<>(target);
    }

    public View getTarget() {
        return mTarget != null ? mTarget.get() : null;
    }


    public int getWidth() {
        return getTarget() != null ? getTarget().getWidth() : 0;
    }

    public int getHeight() {
        return getTarget() != null ? getTarget().getHeight() : 0;
    }

    public void postInvalidate() {
        if (getTarget() != null) {
            getTarget().postInvalidate();//刷新界面
        }
    }

    /**
     * draw indicator
     *
     * @param canvas
     * @param paint
     */
    public abstract void draw(Canvas canvas, Paint paint);

    /**
     * create animation or animations
     */
    public abstract List createAnimation();

    public void initAnimation() {
        mAnimators = createAnimation();
    }

    /**
     * make animation to start or end when target
     * view was be Visible or Gone or Invisible.
     * make animation to cancel when target view
     * be onDetachedFromWindow.
     *
     * @param animStatus
     */
    public void setAnimationStatus(AnimStatus animStatus) {
        if (mAnimators == null) {
            return;
        }
        int count = mAnimators.size();
        for (int i = 0; i < count; i++) {
            Animator animator = mAnimators.get(i);
            boolean isRunning = animator.isRunning();
            switch (animStatus) {
                case START:
                    if (!isRunning) {
                        animator.start();
                    }
                    break;
                case END:
                    if (isRunning) {
                        animator.end();
                    }
                    break;
                case CANCEL:
                    if (isRunning) {
                        animator.cancel();
                    }
                    break;
            }
        }
    }


    public enum AnimStatus {
        START, END, CANCEL
    }


}

定义音乐波动插值器

package com.sun.audioplayingwave.sloading.indicator;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;

import java.util.ArrayList;
import java.util.List;

public class LineScaleWaveIndicator extends BaseIndicatorController {

    public static final float SCALE = 1.0f;

    float[] scaleYFloats = new float[]{SCALE,
            SCALE,
            SCALE,
            SCALE};
    public int[] waveFloats;

    public LineScaleWaveIndicator(int[] waveFloats) {
        this.waveFloats = waveFloats;
    }

    @Override
    public void draw(Canvas canvas, Paint paint) {
        float translateX = getWidth() / 14;
        float translateY = getHeight();
        for (int i = 0; i < 4; i++) {
            canvas.save();
            //平移
            int intRandom = (int) (1 + Math.random() * (10 - 1 + 1));
            float v = intRandom / 10f * getHeight();
            canvas.translate(((i + 1) * 2) * translateX + translateX * i, translateY);
            canvas.scale(SCALE, scaleYFloats[i]);
            RectF rectF = new RectF(-translateX, -getHeight(), 0, 0);
            canvas.drawRoundRect(rectF, 6, 6, paint);
            canvas.restore();
        }
    }

    @Override
    public List createAnimation() {
        List animators = new ArrayList<>();
        long[] delays = new long[]{100, 200, 300, 400};
        for (int i = 0; i < 4; i++) {
            final int index = i;
            ValueAnimator scaleAnim = ValueAnimator.ofFloat(1, 0.4f, 1);
            scaleAnim.setDuration(1000);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleYFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();//刷新界面
                }
            });
            scaleAnim.start();
            animators.add(scaleAnim);
        }
        return animators;
    }

}
package com.sun.audioplayingwave.sloading.indicator;

import android.animation.Animator;
import android.animation.ValueAnimator;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by walkingMen on 2016/4/27.
 */
public class LineScalePulseOutWaveIndicator extends LineScaleWaveIndicator {

    public LineScalePulseOutWaveIndicator(int[] heightFloats) {
        super(heightFloats);
    }

    @Override
    public List createAnimation() {
        List animators = new ArrayList<>();
        long[] delays = new long[]{500, 100, 200, 300};
        for (int i = 0; i < 4; i++) {
            final int index = i;
            ValueAnimator scaleAnim = ValueAnimator.ofFloat(1, 0.3f, 1);
            scaleAnim.setDuration(900);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(waveFloats[i]);
            scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleYFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            scaleAnim.start();
            animators.add(scaleAnim);
        }
        return animators;
    }

}

定义控件的属性

value 新建 attrs.xml


<resources>
    
    <declare-styleable name="SLoadingIndicatorView">
        <attr name="s_indicator">
            <flag name="DefaultScale" value="0"/>
            <flag name="LineScale" value="1"/>
            <flag name="LineScalePulseOut" value="2"/>
            <flag name="LineScalePulseOutThree" value="3"/>
            <flag name="LineScalePulseOutWave" value="4"/>

        attr>
        <attr name="s_indicator_color" format="color"/>
    declare-styleable>
resources>

直接在布局文件中使用

        <com.sun.audioplayingwave.sloading.SLoadingIndicatorView
            android:layout_width="30dp"
            android:layout_height="20dp"
            android:layout_centerInParent="true"
            android:layout_margin="20dp"
            app:s_indicator="LineScalePulseOutWave"/>

你可能感兴趣的:(Android进阶)