实现圆形进度条的拖拽,点击实现效果如下图所示:
自定义属性
在src/values中新建attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="XProgressBar">
<attr name="progress" format="integer"/>
<attr name="max" format="integer"/>
<attr name="smallCircleColor" format="color"/>
<attr name="progressColor" format="color"/>
<attr name="textColor" format="color"/>
<attr name="borderOutWidth" format="dimension"/>
</declare-styleable>
</resources>
在主布局中引用自定义属性
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.xykj.xprogressbar.MainActivity"
android:orientation="vertical">
<com.xykj.view.XProgressBar
android:layout_width="match_parent"
android:layout_height="100dp"
app:progress="30"
app:progressColor="@color/colorAccent"/>
<com.xykj.view.XSeekBar
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginTop="10dp"/>
</LinearLayout>
定义类XProgressBar继承View
public class XProgressBar extends View {
protected int radius;
private int smallRadius;
protected Point center;
protected int progress;
protected int max = 100;
private int borderOutWidth = 20;
private int smallCircleColor = 0xff00A2E8;
private int progressColor = 0xff22B14C;
private int textColor = 0xFFFFFFFF;
private Paint paint;
private RectF progressRect;
public XProgressBar(Context context) {
super(context);
init();
}
public XProgressBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.XProgressBar);
progress = ta.getInteger(R.styleable.XProgressBar_progress, 0);
max = ta.getInteger(R.styleable.XProgressBar_max, 100);
borderOutWidth = ta.getDimensionPixelSize(R.styleable.XProgressBar_borderOutWidth, 20);
smallCircleColor = ta.getColor(R.styleable.XProgressBar_smallCircleColor, 0xff00A2E8);
progressColor = ta.getColor(R.styleable.XProgressBar_progressColor, 0xff22B14C);
textColor = ta.getColor(R.styleable.XProgressBar_textColor, 0xffffffff);
ta.recycle();
init();
}
private void init() {
center = new Point();
progressRect = new RectF();
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(borderOutWidth);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(80, widthMeasureSpec);
int height = getDefaultSize(80, heightMeasureSpec);
center.set(width / 2, height / 2);
radius = width > height ? center.y : center.x;
progressRect.set(center.x - radius + borderOutWidth / 2,
center.y - radius + borderOutWidth / 2,
center.x + radius - borderOutWidth / 2,
center.y + radius - borderOutWidth / 2);
if (smallRadius == 0) {
smallRadius = radius - borderOutWidth - 3;
paint.setTextSize(smallRadius / 2);
}
setMeasuredDimension(width, height);
}
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
int specSize = MeasureSpec.getSize(measureSpec);
if (specSize > size) {
result = specSize;
}
}
return result;
}
Rect textRect = new Rect();
@Override
protected void onDraw(Canvas canvas) {
paint.setStyle(Paint.Style.FILL);
paint.setColor(smallCircleColor);
canvas.drawCircle(center.x, center.y, smallRadius, paint);
String text = progress + "%";
paint.getTextBounds(text, 0, text.length(), textRect);
paint.setColor(textColor);
canvas.drawText(text, center.x - textRect.centerX(),
center.y - textRect.centerY(), paint);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(progressColor);
int degress = getDegress();
canvas.drawArc(progressRect, -90, degress, false, paint);
}
protected int getDegress(){
return 360 * progress / max;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
if (this.progress != progress && progress <= max) {
this.progress = progress;
invalidate();
}
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getBorderOutWidth() {
return borderOutWidth;
}
public void setBorderOutWidth(int borderOutWidth) {
this.borderOutWidth = borderOutWidth;
}
public int getSmallCircleColor() {
return smallCircleColor;
}
public void setSmallCircleColor(int smallCircleColor) {
if(this.smallCircleColor != smallCircleColor) {
this.smallCircleColor = smallCircleColor;
invalidate();
}
}
public int getProgressColor() {
return progressColor;
}
public void setProgressColor(int progressColor) {
if(this.progressColor != progressColor) {
this.progressColor = progressColor;
invalidate();
}
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
if(this.textColor != textColor) {
this.textColor = textColor;
invalidate();
}
}
}
定义类XSeekBar继承XProgressBar
public class XSeekBar extends XProgressBar {
public XSeekBar(Context context) {
super(context);
}
public XSeekBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
private int degress;
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
if (null != onXSeekBarChangeListener) {
onXSeekBarChangeListener.onStartTrackingTouch(this);
}
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
float dis = getDistence(x, y);
if (dis >= radius - 10 && dis <= radius + 10) {
float tanValue = (y - center.y + radius) / Math.abs(x - center.x);
float dPi = (float) Math.atan(tanValue);
int d = (int) Math.toDegrees(dPi);
if (x < center.x) {
d = 180 - d;
}
degress = d * 2;
if (degress > 360) {
degress = 360;
} else if (degress < 0) {
degress = 0;
}
progress = max * degress / 360;
if (null != onXSeekBarChangeListener) {
onXSeekBarChangeListener.onProgressChanged(this, progress, true);
}
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (null != onXSeekBarChangeListener) {
onXSeekBarChangeListener.onStopTrackingTouch(this);
}
break;
}
return true;
}
/**
* 计算触控点到圆心的距离
*
* @param x
* @param y
* @return
*/
private float getDistence(float x, float y) {
return (float) Math.sqrt(Math.pow(x - center.x, 2) + Math.pow(y - center.y, 2));
}
@Override
protected int getDegress() {
return degress;
}
@Override
public void setProgress(int progress) {
if (this.progress != progress && null != onXSeekBarChangeListener) {
onXSeekBarChangeListener.onProgressChanged(this, progress, false);
}
super.setProgress(progress);
}
public OnXSeekBarChangeListener getOnXSeekBarChangeListener() {
return onXSeekBarChangeListener;
}
public void setOnXSeekBarChangeListener(OnXSeekBarChangeListener onXSeekBarChangeListener) {
this.onXSeekBarChangeListener = onXSeekBarChangeListener;
}
private OnXSeekBarChangeListener onXSeekBarChangeListener;
public interface OnXSeekBarChangeListener {
void onStartTrackingTouch(XSeekBar bar);
void onProgressChanged(XSeekBar seekBar, int progress, boolean fromUser);
void onStopTrackingTouch(XSeekBar bar);
}
}