動态圓形進度條
圓形旋轉進度條,外圓弧顔色漸變,内圓弧是兩張顔色不一樣圖案一樣的圖檔,要動态切割畫布切成一個圓弧形。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmL3IDNyUjN1ITMwIDNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
在view裡實作圖檔疊加的效果有兩種方式,一是通過畫筆的paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN))方法去改變porterDuff.Mode的模式,PorterDuff圖檔疊加的模式有16種之多,有興趣自行學下。二是通過裁剪畫布canvas。
第一種方式
/**
* 畫扇形圖檔 通過PorterDuff對圖檔進行裁剪
* @param sourse
* @param min
* @return
*/
public Bitmap drawArcBitmap(Bitmap sourse,int min){
Paint paint = new Paint();
paint.setDither(true);
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min,min, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(target);
RectF rectF = new RectF(arcSize+arcSize/2,arcSize+arcSize/2,width-arcSize-arcSize/2,height-arcSize-arcSize/2);
canvas.drawArc(rectF,270,arcAngle,true,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(newArcBitmap,0,0,paint);
return target;
}
第二種方式
/**
* 畫扇形圖檔 對畫布進行裁剪
* @param canvas
*/
public void drawArcBitmap(Canvas canvas,float rotAngle){
canvas.save();
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Path path = new Path();
RectF rectF = new RectF(arcSize+arcSize/2,arcSize+arcSize/2,width-arcSize-arcSize/2,height-arcSize-arcSize/2);
int radius = (int)(width/2-rectF.left);
float[] xyFloat = caclulatePoint(rotAngle,radius);
path.moveTo(width/2,height/2);
path.lineTo(width/2,rectF.top);
if(arcAngle>=360){
path.lineTo(width/2,rectF.top);
}else{
path.lineTo(xyFloat[0]+width/2,height/2 -xyFloat[1]);
}
path.addArc(rectF,startAngle,rotAngle);
path.close();
canvas.clipPath(path);
canvas.drawBitmap(newArcBitmap,0,0,paint);
canvas.restore();
}
圓形背景
/**
* 畫得到一個圓形的bitmap
* @param sourse
* @param min
* @return
*/
public Bitmap drawCircleBitmap(Bitmap sourse,int min){
Paint paint = new Paint();
paint.setDither(true);
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min,min, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(target);
int radius = min/2-arcSize-arcSize/2;
canvas.drawCircle(min/2,min/2,radius,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(sourse,0,0,paint);
return target;
}
在activity裡調用update方法,傳入參數就可以了。true代表動态,false為靜态顯示
circle_progress.update("65.6",true);
最後在view脫離視窗的時候調用onDetachedFromWindow系統方法回收bitmap
/**
* 對bitmap進行回收
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if(bitmapBac!=null&&bitmapArc!=null&&newArcBitmap!=null&&newBitmapBac!=null){
bitmapBac.recycle();
bitmapBac = null;
bitmapArc.recycle();
bitmapArc = null;
newArcBitmap.recycle();
newArcBitmap = null;
newBitmapBac.recycle();
newBitmapBac = null;
}
}
完整代碼
/**
*
*/
public class MyProgressBar extends ProgressBar{
public MyProgressBar(Context context) {
super(context);
init(context);
}
public MyProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private Context context;
private Paint paint,paintCircle,textPaints,bPaint;
private int textWidth,textHeight;
private int textSize = 80;//文字大小
private int arcSize = 25;//圓弧寬度
private int textColor = Color.GREEN;
private float angle = 360;
private int startAngle = 270;
private String textPrecent="12%";
private SweepGradient mColorShader;
private int width,height;
private Bitmap newBitmapBac,newArcBitmap;
private int[] arcColorByte = new int[2];
private float arcAngle;//圓弧旋轉的度數
private StringBuffer sb = new StringBuffer();
private int[] colorBytes = new int[101];
private float[] positionBytes = new float[2];
private RectF rectF = new RectF();
private String colorString = "#FF4D00";//漸變顔色透明度為0
public void init(Context context){
this.context = context;
ColorBytes();
//漸變圓弧相關
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(arcSize);
//圓相關
paintCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
paintCircle.setStyle(Paint.Style.STROKE);
paintCircle.setStrokeWidth(arcSize);
paint.setColor(Color.parseColor("#454545"));
paintCircle.setAlpha(130);
//文字相關
textPaints = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaints.setColor(textColor);
textPaints.setTextSize(textSize);
//圓形bitmap相關
bPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bPaint.setDither(true);
sb.append("%");
bitmapBac = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_bac1);
bitmapArc = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_bac2);
}
private Bitmap bitmapBac,bitmapArc;
@Override
protected synchronized void onDraw(Canvas canvas) {
//畫圓形bitmap背景
canvas.drawBitmap(drawCircleBitmap(newBitmapBac,width),0,0,bPaint);
//畫扇形bitmap背景
drawArcBitmap(canvas,activeAngle);
//畫漸變圓和非漸變圓
canvas.save();
mColorShader = new SweepGradient(width/2-arcSize,height/2-arcSize,arcColorByte,null);
Matrix matrix = new Matrix();
matrix.setRotate(startAngle,width/2,height/2);
canvas.setMatrix(matrix);
paint.setShader(mColorShader);
rectF = new RectF(arcSize,arcSize,width-arcSize,height-arcSize);
canvas.drawArc(rectF,0,360,false,paintCircle);
canvas.drawArc(rectF,0,activeAngle,false,paint);
canvas.restore();
//畫文字百分比
//計算文字寬高
Rect rect = new Rect();
textPaints.getTextBounds(sb.toString(), 0, sb.toString().length(), rect);
textWidth = rect.width();//文字寬
textHeight = rect.height();//文字高
int textX = width/2-textWidth/2;
int textY = height/2+textHeight/2;
canvas.drawText(sb.toString(),textX,textY,textPaints);
PaintFlagsDrawFilter mSetfil = new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG);
canvas.setDrawFilter(mSetfil);
}
/**
* 更新
* @param sPrecent
* @param isActive //true 為動态,false為靜态
*/
private float activeAngle = 0;
private float activePrecent = 0.0f;
public void update(final String sPrecent,final boolean isActive){
//int colorLength = colorBytes.length;
//int newByteLength = (colorLength*arcAngle)/angle;
try {
double dPrecent = Double.parseDouble(sPrecent);
if(dPrecent>100||dPrecent<0){
return;
}
arcColorByte[0] = colorBytes[0];
arcColorByte[1] = colorBytes[100];
positionBytes[0] = 0.0f;
positionBytes[1] = 1.0f;
final int precent = (int)Math.round(dPrecent);
arcAngle = (angle/101)*precent;//要旋轉的度數
final float junmAngle = arcAngle/(float)precent;
if(isActive){
new Thread(){
@Override
public void run() {
while(isActive){
if(activePrecent>precent){
addStrBuffer(sPrecent);
activePrecent = arcAngle;
postInvalidate();
return;
}
addStrBuffer(activePrecent);
postInvalidate();
activeAngle+=junmAngle;
activePrecent++;
Log.e("precent","precent:"+activePrecent+"----------"+activeAngle);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}else{
addStrBuffer(sPrecent);
activeAngle = arcAngle;
invalidate();
}
}catch (Exception e){
if(e instanceof ClassCastException){
Toast.makeText(context,"必須是string類型的數字才有效",Toast.LENGTH_SHORT).show();
}
e.printStackTrace();
}
}
public <T> void addStrBuffer(T precent){
sb.setLength(0);
sb.append(precent);
sb.append("%");
}
/**
* 系統onMeasure方法
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
//matrix.setScale((float) min/(float)sourse.getWidth(),(float)min/(float)sourse.getHeight());
Matrix matrix = new Matrix();
matrix.setScale((float) width/(float)bitmapBac.getWidth(),(float)height/(float)bitmapBac.getHeight());
newBitmapBac = Bitmap.createBitmap(bitmapBac,0,0,bitmapBac.getWidth(),bitmapBac.getHeight(),matrix,true);
newArcBitmap = Bitmap.createBitmap(bitmapArc,0,0,bitmapArc.getWidth(),bitmapArc.getHeight(),matrix,true);
}
/**
* 畫得到一個圓形的bitmap
* @param sourse
* @param min
* @return
*/
public Bitmap drawCircleBitmap(Bitmap sourse,int min){
Paint paint = new Paint();
paint.setDither(true);
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min,min, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(target);
int radius = min/2-arcSize-arcSize/2;
canvas.drawCircle(min/2,min/2,radius,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(sourse,0,0,paint);
return target;
}
/**
* 畫扇形圖檔 通過PorterDuff對圖檔進行裁剪
* @param sourse
* @param min
* @return
*/
public Bitmap drawArcBitmap(Bitmap sourse,int min){
Paint paint = new Paint();
paint.setDither(true);
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min,min, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(target);
RectF rectF = new RectF(arcSize+arcSize/2,arcSize+arcSize/2,width-arcSize-arcSize/2,height-arcSize-arcSize/2);
canvas.drawArc(rectF,270,arcAngle,true,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(newArcBitmap,0,0,paint);
return target;
}
/**
* 畫扇形圖檔 對畫布進行裁剪
* @param canvas
*/
public void drawArcBitmap(Canvas canvas,float rotAngle){
canvas.save();
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Path path = new Path();
RectF rectF = new RectF(arcSize+arcSize/2,arcSize+arcSize/2,width-arcSize-arcSize/2,height-arcSize-arcSize/2);
int radius = (int)(width/2-rectF.left);
float[] xyFloat = caclulatePoint(rotAngle,radius);
path.moveTo(width/2,height/2);
path.lineTo(width/2,rectF.top);
if(arcAngle>=360){
path.lineTo(width/2,rectF.top);
}else{
path.lineTo(xyFloat[0]+width/2,height/2 -xyFloat[1]);
}
path.addArc(rectF,startAngle,rotAngle);
path.close();
canvas.clipPath(path);
canvas.drawBitmap(newArcBitmap,0,0,paint);
canvas.restore();
}
/**
* 擷取以圓心為軸的x,y坐标
* @param angle
* @param raduis
* @return
*/
private float[] floatsXY = new float[2];
public float[] caclulatePoint(float angle,int raduis) {
//Point point = new Point();
double b = Math.toRadians(angle);
double cos = Math.cos(b);
double sin = Math.sin(b);
double x = raduis * sin;
double y = raduis * cos;
//point.set((int) x, (int) y);
floatsXY[0] = (float) x;
floatsXY[1] = (float) y;
return floatsXY;
}
/**
* 得到一個漸變數組
*/
public void ColorBytes(){
//不直接用string的顔色值是統一換算成8位的顔色值以防止後邊截取字元串報錯
int colorValue = Color.parseColor(colorString);
String hex = Integer.toHexString(colorValue);
Log.e(hex,"hex:"+hex);
for (int i=0;i<colorBytes.length;i++){
int f = 255-(int)(255*(1.0f - i/100.0f));
String newHex = byteToHex(f)+hex.substring(2,8);
BigInteger bi = new BigInteger(newHex, 16);
int value = bi.intValue();
colorBytes[i] = value;
Log.e("value","value:"+newHex);
}
}
private final static String[] hexArray = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
public String byteToHex(int n) {
if (n < 0) { n = n + 256; }
int d1 = n / 16;
int d2 = n % 16;
return hexArray[d1] + hexArray[d2];
}
/**
* 對bitmap進行回收
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if(bitmapBac!=null&&bitmapArc!=null&&newArcBitmap!=null&&newBitmapBac!=null){
bitmapBac.recycle();
bitmapBac = null;
bitmapArc.recycle();
bitmapArc = null;
newArcBitmap.recycle();
newArcBitmap = null;
newBitmapBac.recycle();
newBitmapBac = null;
}
}
}