下载地址: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"/>