您的位置:首页 > 移动开发 > Android开发

android 自定义 环形进度条

2015-11-09 19:17 405 查看
欢迎大家访问我的博客http://blog.csdn.net/mikejaps专注于android
ios app 开发


其实这个控件很简单,继承View,在onDraw 中 绘制一个圆和一个圆弧即可,代码如下,对外暴露了一个设置进度的方法难点主要是数学计算

public class CircleView extends View{
private Paint mPaint;
private int edgeMargin;//进度条与边界的距离
private int rotateRaduis;//圆形进度条的半径
private static final int mMaring = 25;//进度条与罗盘之间的距离
private static final String TAG = "com.example.android.view.MusicRotateView";

private Context mContext;

private Point centPoint;
private Paint Gpaint;
private Paint pPaint;
private RectF oval;

private boolean isDraging;//是否可以拖动小球
private Point mRockBollPosition = new Point();//进度条上的小球位置
private int mRadius = 8;
private int playedRadian;//进度条已经播放的角度

public MusicRotateView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
initValues();
init();
}
private void initValues() {
rotateRaduis = 3*getScreenWidth()/8;
edgeMargin = getScreenWidth()/8;

mPaint = new Paint();//画圆盘的画笔
mPaint.setAntiAlias(true);
mPaint.setColor(Color.parseColor("#FFFFFF"));
centPoint = new Point(rotateRaduis+edgeMargin, rotateRaduis+edgeMargin);

Gpaint = new Paint();//画进度条背景
Gpaint.setColor(Color.GRAY); //设置圆环的颜色
Gpaint.setStyle(Paint.Style.STROKE); //设置空心
Gpaint.setStrokeWidth(8f); //设置圆环的宽度
Gpaint.setAntiAlias(true);  //消除锯齿

pPaint = new Paint();//画进度条进度的画笔
pPaint.setColor(Color.RED); //设置圆环的颜色
pPaint.setStyle(Paint.Style.STROKE); //设置空心
pPaint.setStrokeWidth(8f); //设置圆环的宽度
pPaint.setAntiAlias(true);  //消除锯齿

oval = new RectF((float)(centPoint.x-rotateRaduis),(float)(centPoint.y-rotateRaduis),
(float)(centPoint.x+rotateRaduis),(float)(centPoint.y+rotateRaduis));
}
private void init() {
//InputStream is = getResources().openRawResource(R.drawable.img_record);
//bgBitmap = BitmapFactory.decodeStream(is);
//Matrix matrix = new Matrix();
//float scale = (float)rotateRaduis*2/(float)bgBitmap.getWidth();
//matrix.postScale(scale, scale);
//bgBitmap = Bitmap.createBitmap(bgBitmap,0,0, bgBitmap.getWidth() ,bgBitmap.getHeight() ,matrix, true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(centPoint.x, centPoint.y, rotateRaduis, Gpaint); //画出圆环
canvas.drawArc(oval, 270, playedRadian, false, pPaint);

//		if(isShowRock){
//		}
canvas.drawCircle(mRockBollPosition.x, mRockBollPosition.y, mRadius , mPaint);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(rotateRaduis*2+edgeMargin*2, rotateRaduis*2+edgeMargin*2);
}

private int getScreenWidth(){
WindowManager wm =  (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
return wm.getDefaultDisplay().getWidth();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Point cp ;
Point rp ;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Point np = new Point((int)event.getX(), (int)event.getY());
int distance = distance(centPoint ,np);
System.out.println("distance:"+distance+",小:"+(rotateRaduis-mMaring)+",大:"+(rotateRaduis+mMaring));
cp = new Point((int)event.getX(), (int)event.getY());
rp = getOnRadius(cp);
if(distance>=rotateRaduis-mMaring && distance<=rotateRaduis+mMaring){
mRockBollPosition.set(rp.x,rp.y);
Log.i(TAG, "点下有效");
mRadius = mMaring;
isDraging = true;
//Point pp = new Point((int)event.getX(),(int)event.getY());
flushRadian(centPoint ,cp);
}
break;
case MotionEvent.ACTION_MOVE:
if(isDraging){
cp = new Point((int) event.getX(), (int) event.getY());
rp = getOnRadius(cp);
mRockBollPosition.set(rp.x, rp.y);
flushRadian(centPoint, cp);
}
break;
case MotionEvent.ACTION_UP:
isDraging = false;
mRadius = 8;
break;
default:
break;
}
invalidate();
return true;
}
private Point getOnRadius(Point cp) {
float radian = getRadian(cp, centPoint);
int cX = centPoint.x + (int) (rotateRaduis * Math.cos(radian));
int cY = centPoint.y - (int) (rotateRaduis * Math.sin(radian));
return new Point(cX, cY);
}
private void flushRadian(Point cp, Point pp) {
float lenA = pp.x - cp.x;
float lenB = cp.y - pp.y;
//		float lenC = (float) Math.sqrt(lenA*lenA+lenB*lenB);
float a = lenA/lenB;
//		System.out.println("余数----------》"+a);
double atan = Math.atan(lenA/lenB);
double radian = (atan/Math.PI)*180;
if(pp.x>cp.x){
if(radian>0){
playedRadian = (int) radian;
}else{
playedRadian = (int) (180+radian);
}
}else{
if(radian>=0){
playedRadian = (int) (180+radian);
}else{
playedRadian = (int) (360+radian);
}
}
progressListener.setProgresschanged((float)playedRadian/360f);
//		System.out.println("atan:"+(atan/Math.PI)*180);
}
private int distance(Point cp, Point np) {
try {
int dx = np.x-cp.x;
int dy = np.y -cp.y;
return (int) Math.sqrt(Math.abs(dx*dx)+Math.abs(dy*dy));
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}

/**
* @describe 触摸点与中心点之间直线与水平方向的夹角角
* @param a
* @param b
* @return
*/
public static float getRadian(Point a, Point b) {
float lenA = a.x - b.x;
float lenB = a.y - b.y;
float lenC = (float) Math.sqrt(lenA * lenA + lenB * lenB);
float ang = (float) Math.acos(lenA / lenC);
ang = ang * (b.y < a.y ? -1 : 1);
return ang;
}
/**
* 根据进度条角度刷新小球的位置
*
* @param playedRadian2
*/
private void flushRockPosition(int ang) {
//		mRockBollPosition.s
mRockBollPosition.y = (int) (centPoint.y - (Math.cos(((float)ang/180f)*Math.PI)*rotateRaduis));
mRockBollPosition.x = (int) (centPoint.x + (Math.sin(((float)ang/180f)*Math.PI)*rotateRaduis));
//		Log.i(TAG, "角度ang="+ang);
//		Log.i(TAG, "小球位置x="+mRockBollPosition.x+",y="+mRockBollPosition.y);
}

public void setProgress(float progress){
playedRadian = (int) (360*progress);
flushRockPosition(playedRadian);
invalidate();
}

private ProgressChangedListener progressListener;
public void setProgressListener(ProgressChangedListener progressListener) {
this.progressListener = progressListener;
}

public interface ProgressChangedListener{
void setProgresschanged(float progress);
}
}


效果图如下

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: