金山电池医生充电时,圆中有个波浪动画,正好公司的项目中需要用到这个动画,于是简单实现了下。
思路如下:首先绘制两条曲线,然后分别与绘制的圆进行取交集。
关键代码如下:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Region;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;
public class WaveView extends View {
private Path aboveWavePath = new Path();
private Path blowWavePath = new Path();
private Path mPath = new Path();
private Paint aboveWavePaint = new Paint();
private Paint blowWavePaint = new Paint();
private final int default_above_wave_alpha = 50;
private final int default_blow_wave_alpha = 30;
private final int default_above_wave_color = Color.WHITE;
private final int default_blow_wave_color = Color.WHITE;
private final int default_progress = 80;
private int circleHeight;
private Bitmap circleBitmap;
private Paint paint;
private int waveToTop;
private int aboveWaveColor;
private int blowWaveColor;
private int progress;
private int offsetIndex = 0;
/** wave length */
private final int x_zoom = 100;
/** wave crest */
private final int y_zoom = 40;
/** offset of X */
private final float offset = 0.5f;
private final float max_right = x_zoom * offset;
// wave animation
private float aboveOffset = 0.0f;
private float blowOffset = 4.0f;
/** offset of Y */
private float animOffset = 0.15f;
// refresh thread
private RefreshProgressRunnable mRefreshProgressRunnable;
public WaveView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.waveViewStyle);
}
public WaveView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// load styled attributes.
final TypedArray attributes = context.getTheme()
.obtainStyledAttributes(attrs, R.styleable.WaveView, defStyle,
0);
aboveWaveColor = attributes
.getColor(R.styleable.WaveView_above_wave_color,
default_above_wave_color);
blowWaveColor = attributes.getColor(
R.styleable.WaveView_blow_wave_color, default_blow_wave_color);
progress = attributes.getInt(R.styleable.WaveView_progress,
default_progress);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.argb(255, 207, 60, 11));
paint.setTextSize(22);
setProgress(progress);
initializePainters();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// canvas.drawPath(aboveWavePath, aboveWavePaint);
// 将剪切矩形与要下面要画的矩形相交,只显示相交的区域
canvas.save();
canvas.restore();
mPath.reset();
canvas.drawBitmap(circleBitmap, 0, 0, paint);
mPath.addCircle(circleHeight / 2, circleHeight / 2, circleHeight / 2,
Path.Direction.CW);
canvas.clipPath(mPath, Region.Op.INTERSECT);
canvas.drawPath(blowWavePath, blowWavePaint);
mPath.addCircle(circleHeight / 2, circleHeight / 2, circleHeight / 2,
Path.Direction.CW);
canvas.clipPath(mPath, Region.Op.INTERSECT);
canvas.drawPath(aboveWavePath, aboveWavePaint);
canvas.restore();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measure(widthMeasureSpec, true),
measure(heightMeasureSpec, false));
}
private int measure(int measureSpec, boolean isWidth) {
int result;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
int padding = isWidth ? getPaddingLeft() + getPaddingRight()
: getPaddingTop() + getPaddingBottom();
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = isWidth ? getSuggestedMinimumWidth()
: getSuggestedMinimumHeight();
result += padding;
if (mode == MeasureSpec.AT_MOST) {
if (isWidth) {
result = Math.max(result, size);
} else {
result = Math.min(result, size);
}
}
}
return result;
}
private void initializePainters() {
aboveWavePaint.setColor(aboveWaveColor);
aboveWavePaint.setAlpha(default_above_wave_alpha);
aboveWavePaint.setStyle(Paint.Style.FILL);
aboveWavePaint.setAntiAlias(true);
blowWavePaint.setColor(blowWaveColor);
blowWavePaint.setAlpha(default_blow_wave_alpha);
blowWavePaint.setStyle(Paint.Style.FILL);
blowWavePaint.setAntiAlias(true);
circleBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.count_bg);
circleHeight = circleBitmap.getHeight();
}
/**
* calculate wave track
*/
private void calculatePath() {
aboveWavePath.reset();
blowWavePath.reset();
getWaveOffset();
aboveWavePath.moveTo(0, circleBitmap.getHeight());
for (float i = 0; x_zoom * i <= circleHeight + max_right; i += offset) { //
aboveWavePath.lineTo((x_zoom * i),
(float) (y_zoom * Math.cos(i + aboveOffset)) + waveToTop);
}
aboveWavePath
.lineTo(circleBitmap.getHeight(), circleBitmap.getHeight());
blowWavePath.moveTo(0, circleBitmap.getHeight());
for (float i = 0; x_zoom * i <= circleHeight + max_right; i += offset) { // +
// max_right
blowWavePath.lineTo((x_zoom * i),
(float) (y_zoom * Math.cos(i + blowOffset)) + waveToTop);
}
blowWavePath.lineTo(circleBitmap.getHeight(), circleBitmap.getHeight());
}
public void setProgress(int progress) {
this.progress = progress > 100 ? 100 : progress;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mRefreshProgressRunnable = new RefreshProgressRunnable();
post(mRefreshProgressRunnable);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
removeCallbacks(mRefreshProgressRunnable);
}
private void getWaveOffset() {
if (blowOffset > Float.MAX_VALUE - 100) {
blowOffset = 0;
} else {
blowOffset += animOffset;
}
if (aboveOffset > Float.MAX_VALUE - 100) {
aboveOffset = 0;
} else {
aboveOffset += animOffset;
}
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.progress = progress;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setProgress(ss.progress);
}
private class RefreshProgressRunnable implements Runnable {
public void run() {
synchronized (WaveView.this) {
waveToTop = (int) (circleBitmap.getHeight() * (1f - progress / 100f));
calculatePath();
invalidate();
postDelayed(this, 150);
}
}
}
private static class SavedState extends BaseSavedState {
int progress;
/**
* Constructor called from
* {@link android.widget.ProgressBar#onSaveInstanceState()}
*/
SavedState(Parcelable superState) {
super(superState);
}
/**
* Constructor called from {@link #CREATOR}
*/
private SavedState(Parcel in) {
super(in);
progress = in.readInt();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(progress);
}
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
具体例子可以参考:https://github.com/owen19891030/CircleWave
原文:http://my.oschina.net/owen123456/blog/346199