android 自定义圆形进度条(一)

现在app越来越要求界面很炫,比如一个加载数据的时候,通常是一个进度条在一直转,直到从服务器上获取到数据,进度条才消失,而大部分都不会使用android自带的进度条,因为不美,比如下面的进度条咋样:


其实这个蓝色背景是跟着进度条的进度颜色会发生改变,因为没有找到哪种动态类似gif动画,如果有那个给你,一眼就知道是动态的,虽然不是说非常漂亮,但至少比我们android自带的要美观很多,今天就讲讲这个是怎么实现的,当然了实现重要的是分析,没有一个逻辑的分析,以后遇到类似的还是不会,现在就分析下我是怎么实现的过程:

1:因为是动态的,相当于一个圆的弧度在变小,另外一个圆的弧度在变大,而且是相反方向的,既然说是二个弧度,我们知道在Canvas给我们提供了一个方法drawArc(),因此前面必须有个正方形或者长方形,但是我们这是圆形的进度条,因此需要一个正方形,而圆就是该正方形的内切圆,怎么画出这个正方形呢,很简单,只要知道左上角和右下角2个坐标点即可!

如图:

android 自定义圆形进度条(一)_第1张图片

左上角的点我们可以设置为(0,0).而右下角左边,其实就是getWidth(),getHeight(),因为可以在布局问题中设置了高度和宽度以后就会获取这个控件的宽和高,所以这个正方形就出来了,

2:上面分析了为什么要使用正方形,那么有了这个条件还远不足以让我们实现这个功能,我们知道画弧.是需要你在那开始画,也就是其实点,然后要画多少的弧,那么又给我们带了2个问题,

a:其实弧度,这个很好理解,下面一张图就可以说明问题:


b:其实弧度该怎么算,这个确实有点难,但是你要想有什么已知条件,结合这个已知条件是不是可以获取这个值呢?比如这个控件的高度其实就是圆的直径,当每添加了一个进度,蓝色的背景就会覆盖多点位置,比如这个进度的最大值为100,你移动了1px,那么相当于你在下面往上面移动的高度为1/100*getHeight(),继续画图理解:


现在就可以画弧度了,所有未知的条件都求出来了,现在可以写代码来实现了,新建一个android项目:CustomCircleProgress,然后定义一个类去继承View


现在把代码贴出来,结合刚才的逻辑去看这代码应该没啥问题:

package com.example.customcircleprogress.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import com.example.customcircleprogress.R;
import com.example.customcircleprogress.util.Utils;

public class MyCircleProgress extends View {
	private static final String TAG = MyCircleProgress.class.getSimpleName();
	private final float default_text_size;
    private final int min_size;
	private int progress;//进度条的进度
	private int max;//进度条的最大值
	private Paint textPaint;//画笔  
	private float textSize;
	private int textColor;
	private final int default_text_color = Color.YELLOW;//默认颜色
	private Paint paint = new Paint();
	private RectF rectF = new RectF();
	private final int default_finished_color = Color.rgb(66, 145, 241);
	private final int default_unfinished_color = Color.rgb(204, 204, 204);
	 private int finishedColor;
	 private int unfinishedColor;
	 private String prefixText = "";
	 private String suffixText = "%";
	 private final int default_max = 100;
	public MyCircleProgress(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		 default_text_size = Utils.sp2px(getResources(), 18);//默认文字大小
	     min_size = (int) Utils.dp2px(getResources(), 100);//最小值
	     final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyCircleProgress, defStyle, 0);
         initByAttributes(attributes);
         attributes.recycle();
         initPainters();
	}
	public MyCircleProgress(Context context, AttributeSet attrs) {
		this(context, attrs,0);
	}

	public MyCircleProgress(Context context) {
		this(context,null);
	}
	/**
	 * 画笔的一些设置
	 */
	private void initPainters() {
		 textPaint = new TextPaint();
         textPaint.setColor(textColor);
         textPaint.setTextSize(textSize);
         textPaint.setAntiAlias(true);
         paint.setAntiAlias(true);
	}
	
	private void initByAttributes(TypedArray attributes) {
		finishedColor = attributes.getColor(R.styleable.MyCircleProgress_circle_finished_color, default_finished_color);
	    unfinishedColor = attributes.getColor(R.styleable.MyCircleProgress_circle_unfinished_color, default_unfinished_color);
		textColor = attributes.getColor(R.styleable.MyCircleProgress_circle_text_color, default_text_color);//文字颜色
	    textSize = attributes.getDimension(R.styleable.MyCircleProgress_circle_text_size, default_text_size);//文字大小
	    setMax(attributes.getInt(R.styleable.MyCircleProgress_circle_max, default_max));//设置进度的最大值
		setProgress(attributes.getInt(R.styleable.MyCircleProgress_circle_progress, 0));//
	}
	/**
	 * 给max赋值
	 * @param max
	 */
	private void setMax(int max) {
		if (max > 0) {
            this.max = max;
            invalidate();
        }
	}
	/**
	 * 设置进度
	 * @param int1
	 */
	public void setProgress(int progress) {
		this.progress = progress;
	    if(this.progress > getMax()) {
            this.progress %= getMax();
        }
	    invalidate();//重新绘制界面 ---ondraw()
	}
	/**
	 * 获取最大进度
	 * @return
	 */
	private int getMax() {
		return max;
	}
    public int getProgress() {
        return progress;
    }
    public int getUnfinishedColor() {
        return unfinishedColor;
    }
    public int getFinishedColor() {
        return finishedColor;
    }
    public String getDrawText() {
        return getPrefixText() + getProgress() + getSuffixText();
    }
    public String getPrefixText() {
        return prefixText;
    }
    public String getSuffixText() {
        return suffixText;
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        rectF.set(0, 0, MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));//设置圆的外切  正方形
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
    }
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
	    float yHeight = getProgress() / (float) getMax() * getHeight();
        float radius = getWidth() / 2f;
        float angle = (float) (Math.acos((radius - yHeight) / radius) * 180 / Math.PI);//开始角度
        Log.e(TAG,"angle="+angle);
        float startAngle = 90 + angle;
        float sweepAngle = 360 - angle * 2;
        paint.setColor(getUnfinishedColor());
        canvas.drawArc(rectF, startAngle, sweepAngle, false, paint);

        canvas.save();
        canvas.rotate(180, radius, radius);//围绕圆心旋转180度
        paint.setColor(getFinishedColor());
        canvas.drawArc(rectF, 270 - angle, angle * 2, false, paint);
        canvas.restore();

        String text = getDrawText();
        if (!TextUtils.isEmpty(text)) {
            float textHeight = textPaint.descent() + textPaint.ascent();
            canvas.drawText(text, (getWidth() - textPaint.measureText(text)) / 2.0f, (getWidth() - textHeight) / 2.0f, textPaint);
        }
	}
}
MainActivity.class

	private MyCircleProgress my_custom_circle_progress;
	 private Timer timer;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		my_custom_circle_progress = (MyCircleProgress) findViewById(R.id.my_custom_circle_progress);
		timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
//                        donutProgress.setProgress(donutProgress.getProgress() + 1);
                    	my_custom_circle_progress.setProgress(my_custom_circle_progress.getProgress() + 1);
//                        arcProgress.setProgress(arcProgress.getProgress() + 1);
                    }
                });
            }
        }, 1000, 100);

这是给进度条一个默认值,然后控制它一直循环,‘

attrs下定义了进度条的一些基本属性值 比如颜色,字体大小等,初始进度等:

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <declare-styleable name="MyCircleProgress">
       <attr name="circle_progress" format="integer"/>
       <attr name="circle_text_color" format="color"></attr>
       <attr name="circle_text_size" format="dimension"></attr>
       <attr name="circle_max" format="integer"></attr>
       <attr name="circle_finished_color" format="color"></attr>
       <attr name="circle_unfinished_color" format="color"></attr>
   </declare-styleable>
</resources>

布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <com.example.customcircleprogress.view.MyCircleProgress
        android:id="@+id/my_custom_circle_progress"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
        custom:circle_progress="0"
         />
</RelativeLayout>

ok,如果那里写的不对 或者分析不对,可以提出来,互相学习下!




你可能感兴趣的:(自定义view)