今天貌似生病了……直接来代码
自定义View代码
package com.lizw.circular.wave;
import com.lizw.circular.R;
import com.lizw.circular.R.attr;
import com.lizw.circular.R.drawable;
import com.lizw.circular.R.styleable;
import android.annotation.SuppressLint;
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.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
/**
*
* @author Troy Lee
*
*/
public class CircularView extends View {
//背景圆所在的区域
private final RectF mCircleBounds = new RectF();
// //thumb所在举行
// private final RectF mSquareRect = new RectF();
//底层大圆的画笔
private Paint mBackgroundColorPaint = null;
//底层大圆边宽
private int mCircleStrokeWidth = 10;
private int mGravity = Gravity.CENTER;
//Horizontal的内边界技术依赖于mGravity
private int mHorizontalInset = 0;
//Vertical的内边界技术依赖于mGravity
private int mVerticalInset = 0;
//所有属性设置完成为true,此时在Layout View时候将不会发生错误
private boolean mIsInitializing = true;
//thumb是否可见
private boolean mIsThumbEnabled = true;
//thumb沿着底层圆转的进度
private float mProgress = 0.0f;
//thumb沿着底层圆转前的路径颜色
private int mProgressBackgroundColor;
//thumb沿着底层圆转后留下的路径颜色
private int mProgressColor;
//thumb沿着底层圆转所用的画笔
private Paint mProgressColorPaint;
//底层大圆的半径
private float mRadius;
//thumb的画笔
private Paint mThumbColorPaint = null;
//thumb的坐标 x
private float mThumbPosX;
//thumb的坐 y
private float mThumbPosY;
//thumb的半径
private int mThumbRadius = 20;
//我们用自己坐标系统的变化偏移量X
private float mTranslationOffsetX;
//我们用自己坐标系统的变化偏移量Y
private float mTranslationOffsetY;
/**
* Instantiates a new holo circular progress bar.
*
* @param context the context
*/
public CircularView(final Context context) {
this(context, null);
}
/**
* Instantiates a new holo circular progress bar.
*
* @param context the context
* @param attrs the attrs
*/
public CircularView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.circularProgressBarStyle);
}
/**
* Instantiates a new holo circular progress bar.
*
* @param context the context
* @param attrs the attrs
* @param defStyle the def style
*/
public CircularView(final Context context, final AttributeSet attrs,
final int defStyle) {
super(context, attrs, defStyle);
// load the styled attributes and set their properties
final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircularView,defStyle, 0);
if (attributes != null) {
try {
setProgressColor(attributes.getColor(R.styleable.CircularView_progress_color, Color.CYAN));
setProgressBackgroundColor(attributes.getColor(R.styleable.CircularView_progress_background_color,Color.GREEN));
setProgress(attributes.getFloat(R.styleable.CircularView_progress, 0.0f));
setWheelSize((int) attributes.getDimension(R.styleable.CircularView_stroke_width, 10));
setThumbEnabled(attributes.getBoolean(R.styleable.CircularView_thumb_visible, true));
mGravity = attributes.getInt(R.styleable.CircularView_android_gravity,Gravity.CENTER);
} finally {
// make sure recycle is always called.
attributes.recycle();
}
}
mThumbRadius = mCircleStrokeWidth * 2;
mBackgroundColorPaint = new Paint();
mThumbColorPaint = new Paint();
updateBackgroundColor();
updateProgressColor();
// the view has now all properties and can be drawn
mIsInitializing = false;
}
private Bitmap ballBitmap;
@Override
protected void onDraw(final Canvas canvas) {
// All of our positions are using our internal coordinate system.
// Instead of translating
// them we let Canvas do the work for us.
canvas.translate(mTranslationOffsetX, mTranslationOffsetY);
final float progressRotation = getCurrentRotation();
// // draw the background
canvas.drawArc(mCircleBounds, 270, 360, false,mBackgroundColorPaint);
if (isThumbEnabled()) {
// 根据进度画thumb图标转的路径
canvas.drawArc(mCircleBounds, 270, progressRotation, false,mProgressColorPaint);
//save()作用:在save()方法之前的全都保存,在save()方法之后,restore()方法之前的都清空。
canvas.save();
// 将thumb图标初始位置放到0度
canvas.rotate(progressRotation - 90);
// // 将小方形图标正向旋转45度
// canvas.rotate(45, mThumbPosX, mThumbPosY);
// mSquareRect.left = mThumbPosX - mThumbRadius / 3;
// mSquareRect.right = mThumbPosX + mThumbRadius / 3;
// mSquareRect.top = mThumbPosY - mThumbRadius / 3;
// mSquareRect.bottom = mThumbPosY + mThumbRadius / 3;
// canvas.drawRect(mSquareRect, mThumbColorPaint);
//设置thumb图标为小球
ballBitmap = BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.ic_detectiontrack));
canvas.drawBitmap(ballBitmap, mThumbPosX-ballBitmap.getWidth()/2f, mThumbPosY - ballBitmap.getHeight()/2f, mThumbColorPaint);
canvas.restore();
}
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int height = getDefaultSize(getSuggestedMinimumHeight() + getPaddingTop() + getPaddingBottom() ,heightMeasureSpec);
final int width = getDefaultSize(getSuggestedMinimumWidth() + getPaddingLeft() + getPaddingRight(), widthMeasureSpec);
//所要画出圆形的目标直径
final int diameter;
if (heightMeasureSpec == MeasureSpec.UNSPECIFIED) {
// ScrollView
diameter = width;
computeInsets(0, 0);
} else if (widthMeasureSpec == MeasureSpec.UNSPECIFIED) {
// HorizontalScrollView
diameter = height;
computeInsets(0, 0);
} else {
// Default
diameter = Math.min(width, height);
computeInsets(width - diameter, height - diameter);
}
setMeasuredDimension(diameter, diameter);
final float halfDiameter = diameter * 0.5f;
// 所画圆形的边宽
final float drawedWith;
if (isThumbEnabled()) {
drawedWith = mThumbRadius * (5f / 6f);
} else {
drawedWith = mCircleStrokeWidth / 2f;
}
// 所要画圆形的半径;-10.5f 是为了更好的融入到RectF中,起到padding的作用
mRadius = halfDiameter - drawedWith - 10.5f;
mCircleBounds.set(-mRadius, -mRadius, mRadius, mRadius);
mThumbPosX = (float) (mRadius * Math.cos(0));
mThumbPosY = (float) (mRadius * Math.sin(0));
mTranslationOffsetX = halfDiameter + mHorizontalInset;
mTranslationOffsetY = halfDiameter + mVerticalInset;
}
public int getCircleStrokeWidth() {
return mCircleStrokeWidth;
}
/**
* gives the current progress of the ProgressBar. Value between 0..1 if you set the progress to
* >1 you'll get progress % 1 as return value
*
* @return the progress
*/
public float getProgress() {
return mProgress;
}
/**
* Gets the progress color.
*
* @return the progress color
*/
public int getProgressColor() {
return mProgressColor;
}
/**
* @return true if the marker is visible
*/
public boolean isThumbEnabled() {
return mIsThumbEnabled;
}
/**
* Sets the progress.
*
* @param progress
* the new progress
*/
public void setProgress(final float progress) {
if (progress >= 1.0f) {
mProgress = 1.0f;
} else {
mProgress = progress % 1.0f;
}
// Log.e("", "progress is : " + progress + " ,mProgress is : " + mProgress);
if (!mIsInitializing) {
invalidate();
}
}
/**
* Sets the progress background color.
*
* @param color the new progress background color
*/
public void setProgressBackgroundColor(final int color) {
mProgressBackgroundColor = color;
updateBackgroundColor();
}
/**
* Sets the progress color.
*
* @param color the new progress color
*/
public void setProgressColor(final int color) {
mProgressColor = color;
updateProgressColor();
}
/**
* shows or hides the thumb of the progress bar
*
* @param enabled true to show the thumb
*/
public void setThumbEnabled(final boolean enabled) {
mIsThumbEnabled = enabled;
}
/**
* Sets the wheel size.
*
* @param dimension the new wheel size
*/
public void setWheelSize(final int dimension) {
mCircleStrokeWidth = dimension;
// update the paints
updateBackgroundColor();
updateProgressColor();
}
/**
* Compute insets.
*
* <pre>
* ______________________
* |_________dx/2_________|
* |......| /'''''\|......|
* |-dx/2-|| View ||-dx/2-|
* |______| \_____/|______|
* |________ dx/2_________|
* </pre>
*
* @param dx the dx the horizontal unfilled space
* @param dy the dy the horizontal unfilled space
*/
@SuppressLint("NewApi")
private void computeInsets(final int dx, final int dy) {
int absoluteGravity = mGravity;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
absoluteGravity = Gravity.getAbsoluteGravity(mGravity, getLayoutDirection());
}
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
mHorizontalInset = 0;
break;
case Gravity.RIGHT:
mHorizontalInset = dx;
break;
case Gravity.CENTER_HORIZONTAL:
default:
mHorizontalInset = dx / 2;
break;
}
switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
case Gravity.TOP:
mVerticalInset = 0;
break;
case Gravity.BOTTOM:
mVerticalInset = dy;
break;
case Gravity.CENTER_VERTICAL:
default:
mVerticalInset = dy / 2;
break;
}
}
/**
* Gets the current rotation.
*
* @return the current rotation
*/
private float getCurrentRotation() {
return 360f * mProgress;
}
/**
* updates the paint of the background
*/
private void updateBackgroundColor() {
mBackgroundColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundColorPaint.setColor(mProgressBackgroundColor);
mBackgroundColorPaint.setStyle(Paint.Style.STROKE);
mBackgroundColorPaint.setStrokeWidth(mCircleStrokeWidth);
invalidate();
}
/**
* updates the paint of the progress and the thumb to give them a new visual style
*/
private void updateProgressColor() {
mProgressColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mProgressColorPaint.setColor(mProgressColor);
mProgressColorPaint.setStyle(Paint.Style.STROKE);
mProgressColorPaint.setStrokeWidth(mCircleStrokeWidth);
mThumbColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mThumbColorPaint.setColor(mProgressColor);
mThumbColorPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mThumbColorPaint.setStrokeWidth(mCircleStrokeWidth);
invalidate();
}
}
Activity代码
package com.lizw.circular;
import com.lizw.circular.wave.CircularView;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
/**
* Troy Lee
*/
public class CircularActivity extends Activity {
private static final String TAG = CircularActivity.class.getSimpleName();
/**
* The Switch button.
*/
private CircularView circularView;
private ObjectAnimator objAnimator;
/*
* (non-Javadoc)
*
* @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
circularView = (CircularView) findViewById(R.id.circularView);
}
public void startAnimate(View view) {
animate(circularView,new AnimatorListener() {
@Override
public void onAnimationCancel(final Animator animation) {
circularView.setProgress(0.0f);
}
@Override
public void onAnimationEnd(final Animator animation) {
circularView.setProgress(1.0f);
}
@Override
public void onAnimationRepeat(final Animator animation) {
}
@Override
public void onAnimationStart(final Animator animation) {
circularView.setProgress(0.0f);
}
});
// new Handler().postDelayed(new Runnable() {
//
// @Override
// public void run() {
// // TODO Auto-generated method stub
// if(objAnimator != null){
// objAnimator.cancel();
//
// circularView.setProgress(0.0f);
// }
// }
// }, 3000);
}
/**
* Animate.
*
* @param progressBar the progress bar
* @param listener the listener
*/
private void animate(final CircularView circularView,final AnimatorListener listener) {
final float progress = 1.00f;
int duration = 5000;
circularView.setProgress(0.0f);
animate(circularView, listener, progress, duration);
}
private void animate(final CircularView circularView, final AnimatorListener listener,final float progress, final int duration) {
objAnimator = ObjectAnimator.ofFloat(circularView, "progress", progress);
objAnimator.setDuration(duration);
objAnimator.addListener(new AnimatorListener() {
@Override
public void onAnimationCancel(final Animator animation) {
circularView.setProgress(0.0f);
}
@Override
public void onAnimationEnd(final Animator animation) {
circularView.setProgress(1.0f);
}
@Override
public void onAnimationRepeat(final Animator animation) {
}
@Override
public void onAnimationStart(final Animator animation) {
circularView.setProgress(0.0f);
}
});
if (listener != null) {
objAnimator.addListener(listener);
}
objAnimator.addUpdateListener(new AnimatorUpdateListener() {
float count = 0.0f;
@Override
public void onAnimationUpdate(final ValueAnimator animation) {
count=0.01f;
circularView.setProgress(count);
}
});
// circularView.setMarkerProgress(progress);
objAnimator.start();
}
}
attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircularView">
<attr name="stroke_width" format="dimension" />
<attr name="progress" format="float" />
<attr name="progress_color" format="color" />
<attr name="progress_background_color" format="color" />
<attr name="thumb_visible" format="boolean" />
<attr name="android:gravity" />
</declare-styleable>
<attr name="circularStyle" format="reference" />
</resources>
styles.xml
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Circular">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">match_parent</item>
<item name="stroke_width">5dp</item>
<item name="progress" format="float">0</item>
<item name="progress_color">#46A4EC</item>
<item name="progress_background_color">#adff2f</item>
<item name="thumb_visible">true</item>
</style>
<style name="CircularLight">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">match_parent</item>
<item name="stroke_width">5dp</item>
<item name="progress" format="float">0</item>
<item name="progress_color">#46A4EC</item>
<item name="progress_background_color">#adff2f</item>
<item name="thumb_visible">true</item>
</style>
</resources>
themes.xml
<resources>
<!-- Application theme. -->
<style name="AppTheme" parent="android:Theme.Holo">
<item name="circularStyle">@style/Circular</item>
</style>
<style name="AppThemeLight" parent="android:Theme.Holo.Light">
<item name="circularStyle">@style/CircularLight</item>
</style>
</resources>
activity_home.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/com.lizw.circular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="vertical" >
<com.lizw.circular.wave.CircularView
android:id="@+id/circularView"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="300dp"
app:progress="0" />
<Button
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="startAnimate"
android:text="试试动画"/>
</LinearLayout>
运行效果