package com.app.progressview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
public class ProgressView extends View {
static String MAX = "100%";
private Paint mPaint;
private Rect mTextBound;
private Rect mClipBound;
private float mTextSize; //dp
private int mRadius; //px
private int mColor;
private float mStrokeWidth; //dp
private int mProgress; // progress:[0, 100]
private float offset; //px
private int mTextHeight; //px
public ProgressView(Context context) {
this(context, null);
}
public ProgressView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
void init(Context context, AttributeSet attrs) {
float density = getResources().getDisplayMetrics().density;
//get attrs
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ProgressView);
mTextSize = ta.getDimension(R.styleable.ProgressView_textSize, 16 * density);
mRadius = ta.getDimensionPixelSize(R.styleable.ProgressView_radius, 0);
mColor = ta.getColor(R.styleable.ProgressView_color, Color.BLUE);
mStrokeWidth = ta.getDimension(R.styleable.ProgressView_strokeWidth, 2 * density);
Log.e("TAG", mRadius + " " + mStrokeWidth);
ta.recycle();
//init paint
mPaint = new Paint();
mPaint.setDither(true);
mPaint.setAntiAlias(true);
mPaint.setTextSize(mTextSize);
mPaint.setColor(Color.BLUE);
float strokeWidth = mStrokeWidth;
mPaint.setStrokeWidth(strokeWidth);
offset = strokeWidth / 2;
//text info
mTextBound = new Rect();
//progress
mClipBound = new Rect();
Paint.FontMetricsInt fontMetricsInt = mPaint.getFontMetricsInt();
mTextHeight = fontMetricsInt.descent + fontMetricsInt.ascent;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
//dp,math_parent
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) { //warp_content
mPaint.getTextBounds(MAX, 0, MAX.length(), mTextBound);
width = mTextBound.width();
} else {
width = 0;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
Paint.FontMetricsInt fontMetricsInt = mPaint.getFontMetricsInt();
int ascent = fontMetricsInt.ascent;
int descent = fontMetricsInt.descent;
int textHeight = descent - ascent;
height = textHeight;
} else {
height = 0;
}
setMeasuredDimension(width, height);
}
String mText = "0%";
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int startX;
int startY;
mText = mProgress + "%";
int progress = (int) (width * mProgress / 100.0f);
//確定分割點(diǎn)
mClipBound.left = 0;
mClipBound.top = 0;
mClipBound.right = progress;
mClipBound.bottom = height;
//把文本繪制到中間位置
//獲取文本信息绍弟,確定起點(diǎn)x坐標(biāo)
mPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
startX = (width - mTextBound.width()) / 2;
//獲取文本信息痴颊,確定起點(diǎn)y坐標(biāo)
startY = (height - mTextHeight) / 2;
mPaint.setStyle(Paint.Style.FILL);
//draw left part
canvas.save();
canvas.clipRect(mClipBound);
mPaint.setColor(mColor);
canvas.drawRoundRect(0, 0, width, height, mRadius, mRadius, mPaint);
mPaint.setColor(Color.WHITE);
canvas.drawText(mText, startX, startY, mPaint);
canvas.restore();
mClipBound.left = progress;
mClipBound.top = 0;
mClipBound.right = width;
mClipBound.bottom = height;
//draw right part
canvas.save();
canvas.clipRect(mClipBound);
mPaint.setColor(Color.WHITE);
canvas.drawRoundRect(0, 0, width, height, mRadius, mRadius, mPaint);
mPaint.setColor(mColor);
canvas.drawText(mText, startX, startY, mPaint);
canvas.restore();
//draw outline
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(0 + offset, 0 + offset, width - offset, height - offset, mRadius, mRadius, mPaint);
}
//progress:[0,100]
public void setmProgress(int mProgress) {
if (mProgress >= 0 && mProgress <= 100) {
this.mProgress = mProgress;
invalidate();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ProgressView">
<attr name="textSize" format="reference|dimension" />
<attr name="color" format="reference|color" />
<attr name="radius" format="reference|dimension" />
<attr name="strokeWidth" format="reference|dimension" />
</declare-styleable>
</resources>
package com.app.progressview;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private ProgressView mProgressView;
int progress = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgressView = findViewById(R.id.progressView);
findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onStartClick();
}
});
}
private void onStartClick() {
final Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
if (progress >= 100) {
timer.cancel();
return;
}
progress++;
runOnUiThread(new Runnable() {
@Override
public void run() {
mProgressView.setmProgress(progress);
}
});
}
};
timer.schedule(task, 0, 60);
}
}