效果图
开干
自定义进度条继承View。自定义View主要重写OnMeasure()方法和onDraw()方法。onMeasure方法中主要计算控件的大小,onDraw方法绘制内容。
在计算控件大小的时候要注意测量模式。
先看下不同的测量模式下的打印结果
先设置match_parent 测量模式是EXACTLY
设置指定的大小测量模式还是EXACTLY
设置包裹内容测量模式变成了UNSPECIFIED
增加一个可滑动的父控件,测量模式变成了AT_MOST
不管是UNSPECIFIED还是AT_MOST最后MeasureSpec.getSize(widthMeasureSpec);获取的都是父控件的大小。
package com.test;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
public class MyProgress extends View {
/**
* 背景
*/
private int mBackgroundColor; //背景颜色
private RectF mBgRectF; //背景矩形
private Paint mBgPaint; //bg画笔
/**
* 进度条
*/
private int mProgress=0; //当前进度
private int mProgressColor; //进度颜色
private Paint mProgressPaint; //进度画笔
private RectF mProgressRectF; //进度矩形
/**
* 滑块
*/
private Paint mSliderPaint; //滑块画笔
private RectF mSliderRectF; //滑块矩形
/**
* 进度条的宽高
*/
private int mWidth;
private int mHeight;
private int mRadius;
/**
* 控件的宽高
*/
private int mViewWidth;
private int mViewHeight=0;
/**
* 滑块
*/
private Bitmap circleBitmap;
private int mBitmatWidth;
private int mBitmatHeight;
public MyProgress(Context context) {
this(context,null);
}
public MyProgress(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public MyProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
initPaint();
}
private void init(Context context,AttributeSet attrs) {
TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.MyProgress);
mBackgroundColor=ta.getColor(R.styleable.MyProgress_myProgressBgColor,context.getResources().getColor(R.color.colorLine));
mProgressColor=ta.getColor(R.styleable.MyProgress_myProgressColor,context.getResources().getColor(R.color.text));
mProgress=ta.getColor(R.styleable.MyProgress_myProgress,0);
mHeight=ta.getDimensionPixelSize(R.styleable.MyProgress_myProgressHeight,10);
circleBitmap= BitmapFactory.decodeResource(getResources(),ta.getResourceId(R.styleable.MyProgress_myProgressImg,R.mipmap.img_test));
mRadius=ta.getDimensionPixelSize(R.styleable.MyProgress_myProgressRadius,10);
ta.recycle();
mBitmatWidth = circleBitmap.getWidth();
mBitmatHeight = circleBitmap.getHeight();
}
private void initPaint() {
mBgPaint = new Paint();
mBgPaint.setAntiAlias(true);
mBgPaint.setColor(mBackgroundColor);
mBgPaint.setStyle(Paint.Style.FILL);
mBgPaint.setStrokeCap(Paint.Cap.ROUND);
mSliderPaint = new Paint();
mSliderPaint.setAntiAlias(true);
mSliderPaint.setColor(mProgressColor);
mSliderPaint.setStyle(Paint.Style.FILL);
mSliderPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressPaint = new Paint();
mProgressPaint.setAntiAlias(true);
mProgressPaint.setFilterBitmap(true);//paint抗锯齿(true);
mProgressPaint.setColor(mProgressColor);
mProgressPaint.setStyle(Paint.Style.FILL);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//宽的测量模式
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
//Extracts the size from the supplied measure specification.
//翻译 从提供的度量规范中提取大小 获取指定大小没有就获取父控件的大小
int width=MeasureSpec.getSize(widthMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
int height=MeasureSpec.getSize(heightMeasureSpec);
//EXACTLY == 1073741824
//UNSPECIFIED == -2147483648
//AT_MOST == 0
Log.e("test","widthMode=="+widthMode);
Log.e("test","width=="+width);
int widthSize;
int heightSize;
if(widthMode==MeasureSpec.EXACTLY){ //已经确定具体大小 如设置match_parent或者设置具体值
widthSize=width;
}else{ //没有确定大小
//为了方便随便定义一个大小
widthSize=500;
}
if (heightMode == MeasureSpec.EXACTLY) {
heightSize = height;
} else {
heightSize = mBitmatHeight; //没有定义高度就取滑块的高度
}
mViewWidth = widthSize;
mViewHeight = heightSize;
//进度条的宽度=控件宽-滑块宽
mWidth = mViewWidth - mBitmatWidth;
setMeasuredDimension(mViewWidth, mViewHeight);
}
private PaintFlagsDrawFilter mPaintFilter;
private int left,top,right,bottom;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mPaintFilter == null) {
mPaintFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
//初始化背景的起始位置
left=mBitmatWidth / 2;
top=(mBitmatHeight - mHeight) / 2;
right=(left + mWidth);
bottom=(mBitmatHeight + mHeight)/2;
}
canvas.setDrawFilter(mPaintFilter);//canvas抗锯齿
//画背景
if (mBgRectF == null) {
mBgRectF = new RectF(left, top, right, bottom);
}
canvas.drawRoundRect(mBgRectF, mRadius, mRadius, mBgPaint);
//step2:画进度
//起始位置和背景的起始位置一样
if (mProgress == 0) {
mProgressRectF = new RectF(left, top, left, top);
} else {
mProgressRectF = new RectF(left, top, (mViewWidth-mBitmatWidth)* mProgress/ 100+left, bottom);
}
canvas.drawRoundRect(mProgressRectF, mRadius, mRadius, mProgressPaint);
//step3:画滑块
// canvas.translate(0, -(circleBitmap.getHeight() - mHeight) / 2);
if (mProgress == 0) {
mSliderRectF = new RectF(0, 0, mBitmatWidth, mBitmatHeight);
} else {
mSliderRectF = new RectF((mViewWidth-mBitmatWidth)*mProgress/100 , 0, (mViewWidth-mBitmatWidth)* mProgress/ 100 + mBitmatWidth, mBitmatHeight);
}
canvas.drawBitmap(circleBitmap, null, mSliderRectF, mSliderPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//按下,获取点击的位置
float x = event.getX();
float y = event.getY();
if (x-mBitmatWidth/2-mWidth >= 0) {
mProgress = 100;
} else if (x <= mBitmatWidth / 2) {
mProgress = 0;
} else {
mProgress = (int) ((x-mBitmatHeight/2) * 100 / mWidth);
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
//移动,获取移动后的位置
float x = event.getX();
float y = event.getY();
//触摸在这个控件范围内
if ((y > 0 && y < mBitmatHeight) && ((x>= mBitmatWidth/2) || (x<=mWidth + mBitmatWidth/2))) {
if (x-mBitmatWidth/2-mWidth >= 0) {
mProgress = 100;
} else if (x <= mBitmatWidth / 2) {
mProgress = 0;
} else {
mProgress = (int) ((x-mBitmatHeight/2) * 100 / mWidth);
}
}
}
invalidate();
return true;
}
}
添加自定义属性
<declare-styleable name="MyProgress">
<!--背景颜色-->
<attr name="myProgressBgColor" format="color|reference"/>
<!--进度条颜色-->
<attr name="myProgressColor" format="color|reference"/>
<!--进度-->
<attr name="myProgress" format="integer"/>
<!--进度条的高-->
<attr name="myProgressHeight" format="dimension|reference"/>
<!--中间的图片-->
<attr name="myProgressImg" format="reference"/>
<!--圆角-->
<attr name="myProgressRadius" format="dimension"/>
</declare-styleable>
最后使用
<com.test.MyProgress
android:layout_width="match_parent"
android:layout_height="match_parent" />
最后博客写的少,没写好。不喜勿喷。