Android自定义View绘制圆形、方形、弧形、球形四种形态的模仿下载进度条

本文介绍了如何在Android中创建自定义View,通过继承View并使用Path和Canvas来绘制四种不同形态的进度条:弧形、方形、圆形和球形。实现过程中,首先创建Java类并重写构造器,设置画布尺寸,接着分别绘制四种形状的图形,最后在Activity中利用Handler更新下载进度,达到模仿下载进度条的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

绘制步骤

1.首先创建以JAVA类继承与View,然后调用前两个构造器

2.然后设置画布的宽度和高度

3.绘制图形(见代码)

4.在XML文件布局中添加该View并附上id

5.为了模仿下载进度条,需要在Activity中找到该View,利用Handler提交数据即提交下载完成度,并不断更新View(可以设置延迟来模仿)

6.代码实现

弧形进度条

自定义View

public class ProgressArcView extends View {
    private int width;
    private int heigth;
    private int progressCurrent;
    private int progressMax=100;
    private Paint mPaintMax;
    private Paint mPaintCurrent;
    private Paint mPaintText;
    public void setProgressCurrent(int progressCurrent) {
        this.progressCurrent = progressCurrent;
        invalidate();
    }
    public ProgressArcView(Context context) {
        super(context);
    }

    public ProgressArcView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaintMax=new Paint();
        mPaintMax.setAntiAlias(true);
        mPaintMax.setColor(Color.GRAY);
        mPaintMax.setStyle(Paint.Style.STROKE);
        mPaintMax.setStrokeWidth(100);

        mPaintCurrent=new Paint();
        mPaintCurrent.setAntiAlias(true);
        mPaintCurrent.setColor(Color.BLUE);
        mPaintCurrent.setStyle(Paint.Style.STROKE);
        mPaintCurrent.setStrokeWidth(100);

        mPaintText=new Paint();
        mPaintText.setAntiAlias(true);
        mPaintText.setColor(Color.BLACK);
        mPaintText.setTextAlign(Paint.Align.CENTER);
        mPaintText.setTextSize(80);
    }
    //设置画布的宽度和高度
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width=getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        heigth=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width,heigth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(width/2,heigth/2,300,mPaintMax);//画一个圆是以总宽度和总高度的二分之一为圆心,300为半径
        //定义一个矩形,这个矩形是圆的外切正方形,其距离屏幕左边width/2-300,距离屏幕上边heigth/2-300
        //其距离屏幕左边width/2+300的距离为右边缘,距离屏幕上边heigth/2+300的距离设置为底
        RectF rectF=new RectF(width/2-300,heigth/2-300,width/2+300,heigth/2+300);
        //画弧,在矩形内画,开始角度为-90度,然后是进度,
        //Boolean值表示是否显示表示半径的那一条线
        canvas.drawArc(rectF,-90,progressCurrent*360f/progressMax,false,mPaintCurrent);
        canvas.drawText(progressCurrent*100f/progressMax+"%",width/2,heigth/2,mPaintText);
    }
}

Activity

public class ProgressArcActivity extends AppCompatActivity {
    private Button mBtnProgressArc;
    private int progress=0;
    private ProgressArcView mProArc;
    public static final int PROGRESS_ARC=0x62;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case PROGRESS_ARC:
                    progress++;
                    if (progress<=100){
                        mProArc.setProgressCurrent(progress);
                        handler.sendEmptyMessageDelayed(PROGRESS_ARC,100);
                    }
                    break;
                default:
                    break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.progress_arc);
        mProArc= (ProgressArcView) findViewById(R.id.progress_arc);
        mBtnProgressArc= (Button) findViewById(R.id.button_start_arc);
        mBtnProgressArc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.sendEmptyMessage(PROGRESS_ARC);
            }
        });
    }
}

XML文档

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button_start_arc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始"/>
    <com.my.mywidget.widget.ProgressArcView
        android:id="@+id/progress_arc"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</LinearLayout>

绘制方形和圆形进度条,只有绘制的图形不一样,其他代码都相同

绘制方形
 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //定义一个正方形,其距离屏幕左边width/4,距离屏幕上边heigth/4
        //其距离屏幕左边width*3/4的距离为右边缘,距离屏幕上边heigth*3/4的距离设置为底
        canvas.drawRect(width/4,heigth/4,width*3/4,heigth*3/4,mPaintMax);
        canvas.drawRect(width/4,heigth*3/4-(heigth*progressCurrent*2f/progressMax)/4,width*3/4,heigth*3/4,mPaintCurrent);
        canvas.drawText(progressCurrent*100f/progressMax+"%",width/2,heigth/2,mPaintText);
    }
绘制圆形

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(width/2,heigth/2,300,mPaintMax);
        canvas.drawCircle(width/2,heigth/2,300f*progressCurrent/progressMax,mPaintCurrent);
        canvas.drawText(progressCurrent*100f/progressMax+"%",width/2,heigth/2,mPaintText);

    }

绘制球形进度

public class ProgressSphere extends View {
    private int width;
    private int heigth;
    private int progress;
    private Bitmap mBitmap;
    private Canvas mCanvasBit;
    private Paint mPaintNormal;
    private Paint mPaintPoint;
    private Paint mPaintText;
    private Path mPath;
    public static final int REFRESH=0x55;
    private int count=0;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case REFRESH:
                    count+=10;//count的作用是为了让波浪线动起来
                    if (count>100) {
                        count = 0;
                    }
                    progress+=1;
                    if (progress>=200){
                        progress=0;
                    }
                    handler.sendEmptyMessageDelayed(REFRESH,100);
                    invalidate();
                    break;
            }
        }
    };
    public ProgressSphere(Context context) {
        super(context);
    }

    public ProgressSphere(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaintNormal=new Paint();
        mPaintNormal.setColor(Color.CYAN);
        mPaintNormal.setStyle(Paint.Style.FILL);
        mPaintNormal.setAntiAlias(true);
        PorterDuffXfermode mode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
        mPaintNormal.setXfermode(mode);

        mPaintPoint=new Paint();
        mPaintPoint.setColor(Color.GRAY);
        mPaintPoint.setAntiAlias(true);
        mPaintPoint.setStyle(Paint.Style.FILL);
        mPaintPoint.setStrokeWidth(2);

        mPaintText=new Paint();
        mPaintText.setTextSize(50);
        mPaintText.setColor(Color.BLACK);
        mPaintText.setTextAlign(Paint.Align.CENTER);

        mPath=new Path();

        handler.sendEmptyMessage(REFRESH);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width=getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        heigth=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width,heigth);
        mBitmap=Bitmap.createBitmap(width,heigth, Bitmap.Config.ARGB_8888);
        mCanvasBit=new Canvas(mBitmap);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        canvas.drawColor(Color.CYAN);
        canvas.drawBitmap(mBitmap,0,0,null);
        mCanvasBit.drawCircle(360,500,100,mPaintPoint);
        //利用贝塞尔曲线绘制动态波浪
        mPath.reset();
        mPath.moveTo(500, 600-progress);
        mPath.lineTo(500,650);
        mPath.lineTo(count,650);
        mPath.lineTo(count, 600-progress);
        //循环绘制波浪线
        for (int i=0;i<10;i++) {
            //这两个绘制贝塞尔曲线会连接成为一个波浪线
            mPath.rQuadTo(20, 6, 50, 0);//rquadTo是按照该点(即count,500这个点)为原点进行绘制操作
            mPath.rQuadTo(20, -6, 50, 0);//上一个绘制完成后的终点,成为该rQuadTo的起点(即原点)重新开始绘制
        }

        mPath.close();
        mCanvasBit.drawPath(mPath,mPaintNormal);
        mCanvasBit.drawText(progress*100/200f+"%",360,500,mPaintText);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值