码迷,mamicode.com
首页 > 其他好文 > 详细

仿金山电池医生动画

时间:2014-11-19 11:36:48      阅读:221      评论:0      收藏:0      [点我收藏+]

标签:android   style   http   io   ar   color   os   sp   for   

金山电池医生充电时,圆中有个波浪动画,正好公司的项目中需要用到这个动画,于是简单实现了下。

思路如下:首先绘制两条曲线,然后分别与绘制的圆进行取交集。

关键代码如下:

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

仿金山电池医生动画

标签:android   style   http   io   ar   color   os   sp   for   

原文地址:http://my.oschina.net/owen123456/blog/346199

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!