Android高级UI开发(三十九)绘制圆环和圆弧进度
【摘要】 今天我们用Paint,Canvas在自定义View中绘制一个圆环,点击圆环后自动在圆环上绘制弧形进度,示意图如下:1. 我们先看一下页面布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" an...
-
今天我们用Paint,Canvas在自定义View中绘制一个圆环,点击圆环后自动在圆环上绘制弧形进度,示意图如下:
-
1. 我们先看一下页面布局文件:
-
<RelativeLayout
-
xmlns:android="http://schemas.android.com/apk/res/android"
-
android:layout_width="match_parent"
-
android:layout_height="match_parent"
-
android:paddingBottom="16dp"
-
android:paddingLeft="16dp"
-
android:paddingRight="16dp"
-
android:paddingTop="16dp"
-
xmlns:app="http://schemas.android.com/apk/res-auto">
-
<com.draw.draw_circleprogressbar.CircleProgressBar
-
android:id="@+id/progressbar"
-
android:layout_width="200dp"
-
android:layout_height="200dp"
-
app:roundProgressColor="#ff00ff"
-
app:textColor="#000066"
-
app:textSize="20dp"
-
app:roundWidth="15dp"
-
/>
-
</RelativeLayout>
-
其中CircleProgressBar是我们自定义的View,刚开始绘制一个圆环,点击View会绘制弧形进度。接下来我们先看一下它在MainActivity的用法。
-
-
2. CircleProgressBar在MainActivity中的使用
-
-
MainActivity.java代码如下:
-
-
package com.draw.draw_circleprogressbar;
-
import android.support.v7.app.AppCompatActivity;
-
import android.os.Bundle;
-
import android.view.View;
-
-
public class MainActivity extends AppCompatActivity {
-
private CircleProgressBar mProgressbar;
-
private int progress = 0;
-
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView( R.layout.activity_main);
-
mProgressbar = (CircleProgressBar) findViewById(R.id.progressbar);
-
-
mProgressbar.setOnClickListener(new View.OnClickListener() {
-
@Override
-
public void onClick(View v) {
-
new Thread(new Runnable() {
-
@Override
-
public void run() {
-
while (progress <= 100){
-
progress += 2;
-
mProgressbar.setProgress(progress);
-
-
try {
-
Thread.sleep(100);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
-
}
-
}).start();
-
-
}
-
});
-
-
}
-
}
-
mProgressbar.setOnClickListener里我们每隔100ms让进度+2.很简单在这里不再赘述。
-
接下来我们详细了解下CircleProgressBar是如何自定义的。
-
-
3. 自定义控件CircleProgressBar
-
CircleProgressBar.java如下:
-
-
package com.draw.draw_circleprogressbar;
-
-
import android.content.Context;
-
import android.content.res.TypedArray;
-
import android.graphics.Canvas;
-
import android.graphics.Color;
-
import android.graphics.Paint;
-
import android.graphics.RectF;
-
import android.graphics.Typeface;
-
import android.support.annotation.Nullable;
-
import android.util.AttributeSet;
-
import android.view.View;
-
/**
-
* Created by xw modify on 2018/5/8.
-
*/
-
-
public class CircleProgressBar extends View{
-
private int max;
-
private int roundColor;
-
private int roundProgressColor;
-
private int textColor;
-
private float textSize;
-
private float roundWidth;
-
private boolean textShow;
-
private int progress;
-
private Paint paint;
-
public static final int STROKE = 0;
-
public static final int FILL = 1;
-
-
public CircleProgressBar(Context context, @Nullable AttributeSet attrs) {
-
super(context, attrs);
-
paint = new Paint();
-
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar);
-
max = typedArray.getInteger(R.styleable.CustomProgressBar_max, 100);
-
roundColor = typedArray.getColor(R.styleable.CustomProgressBar_roundColor, Color.RED);
-
roundProgressColor = typedArray.getColor(R.styleable.CustomProgressBar_roundProgressColor, Color.BLUE);
-
textColor = typedArray.getColor(R.styleable.CustomProgressBar_textColor, Color.GREEN);
-
textSize = typedArray.getDimension(R.styleable.CustomProgressBar_textSize, 55);
-
roundWidth = typedArray.getDimension(R.styleable.CustomProgressBar_roundWidth, 10);
-
textShow = typedArray.getBoolean(R.styleable.CustomProgressBar_textShow, true);
-
typedArray.recycle();
-
}
-
-
@Override
-
protected void onDraw(Canvas canvas) {
-
super.onDraw(canvas);
-
-
//画背景圆环
-
int center = getWidth() / 2;
-
float radius = center - roundWidth / 2;
-
paint.setColor(roundColor);
-
paint.setStyle(Paint.Style.STROKE);
-
paint.setStrokeWidth(roundWidth); // 圆环的宽度
-
paint.setAntiAlias(true);
-
canvas.drawCircle(center,center,radius,paint);
-
-
// 画进度百分比
-
paint.setColor(textColor);
-
paint.setStrokeWidth(0);
-
paint.setTextSize(textSize);
-
paint.setTypeface(Typeface.DEFAULT_BOLD);
-
-
int percent = (int)(progress / (float)max * 100);
-
String strPercent = percent + "%";
-
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
-
if(percent != 0){
-
canvas.drawText(strPercent, getWidth() / 2 - paint.measureText(strPercent) / 2 ,
-
getWidth() / 2 +(fm.bottom - fm.top)/2 - fm.bottom, paint);
-
}
-
// 画圆弧
-
RectF oval = new RectF(center - radius, center - radius,
-
center + radius, center + radius);
-
paint.setColor(roundProgressColor);
-
paint.setStrokeWidth(roundWidth);
-
paint.setStyle(Paint.Style.STROKE);
-
paint.setStrokeCap(Paint.Cap.ROUND);
-
canvas.drawArc(oval, 0 , 360 * progress / max, false, paint);
-
}
-
-
public void setProgress(int progress){
-
if(progress < 0 ){
-
throw new IllegalArgumentException("进度Progress不能小于0");
-
}
-
if(progress > max){
-
progress = max;
-
}
-
if(progress <= max){
-
this.progress = progress;
-
postInvalidate();
-
}
-
}
-
}
-
首先在CircleProgressBar构造函数里读取XML属性,比如roundColor圆环颜色,
-
roundProgressColor圆弧进度的颜色,textColor圆中心文字的颜色,textSize文字大小,
-
roundWidth圆环的宽度。接下来我们分析核心代码onDraw函数,
-
它总共分为3部分:绘制圆环、绘制文字、绘制圆弧进度
-
-
3.1 绘制圆环
-
-
//画背景圆环
-
int center = getWidth() / 2;
-
float radius = center - roundWidth / 2;
-
paint.setColor(roundColor);
-
paint.setStyle(Paint.Style.STROKE);
-
paint.setStrokeWidth(roundWidth); // 圆环的宽度
-
paint.setAntiAlias(true);
-
canvas.drawCircle(center,center,radius,paint);
-
-
canvas.drawCircle(center,center,radius,paint);函数,
-
参数:center,center圆心的x,y坐标,即这个自定义控件View的中心,getWidth() / 2;
-
参数:radius:园的半径,
-
getWidth() / 2 - roundWidth / 2 = center - roundWidth / 2;
-
即圆的半径是指从圆心 到 园环(园周)宽度中心的距离。
-
参数:paint: 画笔,在这里设置了画笔的颜色,风格为STROKE模式,圆环宽度,抗锯齿等。
-
-
3.2 绘制文字
-
-
// 画进度百分比
-
paint.setColor(textColor);
-
paint.setStrokeWidth(0);
-
paint.setTextSize(textSize);
-
paint.setTypeface(Typeface.DEFAULT_BOLD);
-
-
int percent = (int)(progress / (float)max * 100);
-
String strPercent = percent + "%";
-
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
-
if(percent != 0){
-
canvas.drawText(strPercent, getWidth() / 2 - paint.measureText(strPercent) / 2 ,
-
getWidth() / 2 +(fm.bottom - fm.top)/2 - fm.bottom, paint);
-
}
-
-
这里主要看一下canvas.drawText的各参数:
-
strPercent:要绘制的文本内容如“70%”;
-
x: 文字相对于View的水平位置,即圆的中心getWidth() / 2 ,放在中心位置还不对,因为x代表的是文本的最左边的x坐标,要想文字居中,
-
还得用getWidth() / 2- paint.measureText(strPercent) / 2 ,即园心位置 在往左偏移 文本内容的一半宽度。
-
y: 表示文本strPercent的基线Y坐标。我们称它为baseline。其实文本除了有基线,还有其它4条表示文本位置的线,如下图所示。
-
-
这里我们需要计算baseline,公式是:baseline = center +(FontMetrics.bottom - FontMetrics.top)/2 - FontMetrics.bottom
-
其中center是文本内容的垂直中分线的y坐标(相对于View的顶端的y坐标),如上图中的center所示。
-
-
3.3 绘制圆弧进度
-
-
paint.setStrokeCap(Paint.Cap.ROUND);
-
这个是设置笔帽的,比如你把铅笔头磨成方的还是圆的(线的两端点是圆头的),或者是尖的(正常情况下画出来就是直线)
-
canvas.drawArc(oval, 0 , 360 * progress / max, false, paint);
-
绘制弧度,其中oval是一个rect,360 * progress / max是进度,false是不填充圆的内部区域,paint画笔。
-
-
3.4 设置进度setProgress
-
-
只有不断设置进度并调用postInvalidate函数才能出发onDraw函数重新绘制圆弧的进度。
-
-
好了,到此这个圆环和圆弧进度的动态绘制就讲完了。
-
源码:
https://download.csdn.net/download/gaoxiaoweiandy/12089175
文章来源: blog.csdn.net,作者:冉航--小虾米,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/gaoxiaoweiandy/article/details/103887605
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)