✍ Author by NamCooper
1> 效果图如下:
2> 实现细节:
①分析结构:
做一个完全自定义View,熟悉api当然是很重要的,但是明确实现结果和步骤同样非常关键。按照上面的效果图,我们可以很容易分析出,这个自定义View的绘制分为3个部分:底层矩形框(灰色框)、进度矩形框(红色框)、文本,而这三种结构在View的onDraw方法中,可以使用canvas的两个方法来实现:canvas.drawRect(),canvas.drawText()。
①代码实现,自定义一个RectProgressBar继承View,实现步骤见代码注释:
public class RectProgressBar extends View {
private Context mContext;
//可配置项
private int bgColor = Color.GRAY;
private int upColor = Color.RED;
private int txtColor = Color.GREEN;
private int pro_width = 8;
private int txtSize = 15;
private int pro_num = 0;
private Paint bgPaint;
private Paint upPaint;
private Paint txtPaint;
private int height;
private int width;
private Rect rect;
private float top;
private float bottom;
private int baseLineY = -1;
public RectProgressBar(Context context) {
this(context, null);
}
public RectProgressBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
}
public RectProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
bgPaint = new Paint();
bgPaint.setAntiAlias(true);
bgPaint.setColor(bgColor);
bgPaint.setStyle(Paint.Style.STROKE);
bgPaint.setStrokeWidth((float) (dip2px(mContext, pro_width * 2)));
upPaint = new Paint();
upPaint.setAntiAlias(true);
upPaint.setColor(upColor);
upPaint.setStyle(Paint.Style.FILL);
txtPaint = new Paint();
txtPaint.setAntiAlias(true);
txtPaint.setColor(txtColor);
txtPaint.setTextSize((float) (dip2px(mContext, txtSize)));
//该方法即为设置基线上那个点究竟是left,center,还是right 这里我设置为center
txtPaint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetrics fontMetrics = txtPaint.getFontMetrics();
//为基线到字体上边框的距离
top = fontMetrics.top;
//为基线到字体下边框的距离
bottom = fontMetrics.bottom;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
//计算文字所处的
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (rect == null) {
rect = new Rect(0, 0, width, height);
}
if (baseLineY < 0) {
baseLineY = (int) (rect.centerY() - top / 2 - bottom / 2);//基线中间点的y轴计算公式
}
//画背景条
canvas.drawRect(rect, bgPaint);
//画文字
canvas.drawText(pro_num + "%", rect.centerX(), baseLineY, txtPaint);
//画进度
if (pro_num >= 0 && pro_num <= 25) {
//0-25进度,只画上边
drawTop(canvas, pro_num);
} else if (pro_num > 25 && pro_num <= 50) {
//25-50,画上边和右边
drawTop(canvas, 25);
drawRight(canvas, pro_num);
} else if (pro_num > 50 && pro_num <= 75) {
//50-75,除了左边都要画
drawTop(canvas, 25);
drawRight(canvas, 50);
drawBottom(canvas, pro_num);
} else if (pro_num > 70 && pro_num <= 100) {
//75-100,四条边都要画
drawTop(canvas, 25);
drawRight(canvas, 50);
drawBottom(canvas, 75);
drawLeft(canvas, pro_num);
} else {
throw new RuntimeException("the rate must between 0 and 100");
}
}
/**
* 设置背景框颜色
* @param color
*/
public void setBgColor(int color) {
bgColor = color;
bgPaint.setColor(bgColor);
invalidate();
}
/**
* 设置进度条颜色
* @param color
*/
public void setUpColor(int color) {
upColor = color;
upPaint.setColor(upColor);
invalidate();
}
/**
* 设置文本颜色
* @param color
*/
public void setTxtColor(int color) {
txtColor = color;
txtPaint.setColor(txtColor);
invalidate();
}
/**
* 设置进度条宽度
* @param widthDp dp单位
*/
public void setPro_width(int widthDp) {
pro_width = widthDp;
bgPaint.setStrokeWidth((float) (dip2px(mContext, pro_width * 2)));
invalidate();
}
/**
* 设置文本字体大小
* @param sizeSp sp单位
*/
public void setTextSize(int sizeSp) {
txtSize = sizeSp;
txtPaint.setTextSize((float) (dip2px(mContext, txtSize)));
invalidate();
}
/**
* 设置进度
* @param pro_num
*/
public void setPro_num(int pro_num) {
this.pro_num = pro_num;
invalidate();
}
private void drawLeft(Canvas canvas, float pro_num) {
canvas.drawRect(
0
, (1 - (pro_num - 75) * 1f / 25) * (height - (float) (dip2px(mContext, pro_width)))
, (float) (dip2px(mContext, pro_width))
, height - (float) (dip2px(mContext, pro_width))
, upPaint);
}
private void drawBottom(Canvas canvas, float pro_num) {
canvas.drawRect(
(1 - ((pro_num - 50) * 1f / 25)) * (width - (float) (dip2px(mContext, pro_width)))
, height - (float) (dip2px(mContext, pro_width))
, width - (float) (dip2px(mContext, pro_width))
, height
, upPaint);
}
private void drawRight(Canvas canvas, float pro_num) {
canvas.drawRect(
width - (float) (dip2px(mContext, pro_width))
, (float) (dip2px(mContext, pro_width))
, width
, (pro_num - 25) * 1f / 25 * (height - (float) (dip2px(mContext, pro_width))) + (float) (dip2px(mContext, pro_width))
, upPaint);
}
private void drawTop(Canvas canvas, float pro_num) {
canvas.drawRect((float) (dip2px(mContext, pro_width))
, 0
, (pro_num * 1f / 25 * (width - (float) (dip2px(mContext, pro_width)))) + (float) (dip2px(mContext, pro_width))
, (float) (dip2px(mContext, pro_width))
, upPaint);
}
public double dip2px(Context context, double dpValue) {
float density = context.getResources().getDisplayMetrics().density;
return dpValue * (double) density + 0.5D;
}
}
3> 核心api说明:
canvas.drawRect(left,top,right,bottom,paint):
-left:左上点x坐标
-top:左上点y坐标
-right:右下点x坐标
-bottom:右下点y坐标
-paint:用于绘制矩形的画笔
canvas.drawText(text,x,y,paint):
该方法的详细介绍请参见大神作品android canvas drawText()文字居中。
4> 使用:
<RelativeLayout
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.namcooper.widgetdemos.activity.RectProgressBarActivity">
<com.namcooper.widgetdemos.widget.RectProgressBar
android:id="@+id/rpb_pb"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true"/>
<Button
android:onClick="startAnim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:text="开启动画"/>
RelativeLayout>
5> 调用:
public class RectProgressBarActivity extends AppCompatActivity {
private RectProgressBar progressBar;
private Timer timer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rect_progress_bar);
progressBar = (RectProgressBar) findViewById(R.id.rpb_pb);
progressBar.setBgColor(Color.BLACK);
progressBar.setUpColor(Color.GREEN);
progressBar.setPro_width(20);
progressBar.setTextSize(20);
progressBar.setTxtColor(Color.RED);
}
public void startAnim(View v) {
ValueAnimator animator = ValueAnimator.ofInt(0, 100);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int x = (int) animation.getAnimatedValue();
progressBar.setPro_num(x);
}
});
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(5000);
animator.start();
}
}
6> 效果如下: