Fork me on GitHub
文章目录
  1. 1. 前言
  2. 2. 我的想法
  3. 3. 关于onDraw和dispatchDraw
  4. 4. CircleProgressView.java
  5. 5. activity_main.xml
  6. 6. MainActivity.java
  7. 7. 感谢

前言


自定义View有多种实现类型,分别为继承自View完全自定义,继承自现有控件(如ImageView)实现特定效果,继承自ViewGroup实现布局类.这里面涉及到View的测量和布局,View的绘制,处理触摸事件,动画等.

这次实现自定义圆形进度条,我使用的是继承LinearLayout的方式.最终的实现效果如下:

图片1

图片2

图片3

我的想法


要实现这个简单的效果,我的想法是,将circle_progress_view作为背景,进度条用Paint画一条弧实现,作为子组件.只要当前进度发生变化,就进行重绘.

circle_progress_view.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentRight="true"
android:gravity="center"
android:orientation="vertical">


<ImageView
android:id="@+id/cpv_iv_icon"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/ic_download" />


<TextView
android:id="@+id/cpv_tv_des"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="下载" />


</LinearLayout>

关于onDraw和dispatchDraw


绘制View本身的内容,调用View.onDraw方法;绘制自己的孩子,则通过dispatchDraw来实现.

View组件的绘制先是调用draw方法绘制背景,在画完背景之后,draw方法会调用onDraw,然后是调用dispatchDraw方法,分发子组件的绘制.

上面有提到,将circle_progress_view作为背景,将弧形进度条作为子组件,所以只要在dispatchDraw方法中加入对弧形进度条的绘制就行了,很简单!

CircleProgressView.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
* Copyright (C) 1996-2016 YONGF Inc.All Rights Reserved.
* Scott Wang blog.54yongf.com | blog.csdn.net/yongf2014
* 文件名: CircleProgressView
* 描述:
* 修改历史:
* 版本号 作者 日期 简要介绍相关操作
* 1.0 Scott Wang 16-4-21 新增:Create
*/


package com.yongf.circleprogressview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
* ${description}
*
* @author Scott Wang
* @version 1.0, 16-4-21
* @see
* @since 1.0
*/

public class CircleProgressView extends LinearLayout {

private ImageView mIcon;
private TextView mDesc;

private boolean mProgressEnable = true;
private long mMax = 100;
private long mProgress;

public CircleProgressView(Context context) {
this(context, null);
}

public CircleProgressView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

View view = View.inflate(context, R.layout.circle_progress_view, this);

mIcon = (ImageView) view.findViewById(R.id.cpv_iv_icon);
mDesc = (TextView) view.findViewById(R.id.cpv_tv_des);
}

/**
* 设置进度条的背景图片
*
* @param resId
*/

public void setIcon(int resId) {
mIcon.setImageResource(resId);
}

/**
* 设置自定义进度条的提示文字
*
* @param desc
*/

public void setDesc(String desc) {
mDesc.setText(desc);
}

/**
* 设置开启进度条的显示,默认关闭
*
* @param progressEnable
*/

public void setProgressEnable(boolean progressEnable) {
mProgressEnable = progressEnable;
}

/**
* 设置最大进度值,默认为100
*
* @param max
*/

public void setMax(long max) {
mMax = max;
}

/**
* 设置当前进度
*
* @param progress
*/

public void setProgress(long progress) {
mProgress = progress;

invalidate();
}

@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas); //绘制背景

if (mProgressEnable) {
RectF oval = new RectF(mIcon.getLeft(), mIcon.getTop(), mIcon.getRight(), mIcon.getBottom()); //以背景图片为基础画一个矩形
float startAngle = -90; //-90相当于就是"正北"

float sweepAngle = mProgress * 360.f / mMax; //旋转的角度

boolean useCenter = false; //是否保留两边的半径

Paint paint = new Paint();
paint.setColor(Color.BLUE); //蓝色的画笔
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5); //设置画笔的粗细,也就是进度条的粗细
paint.setAntiAlias(true); //消除锯齿
// 开始画一条弧,表示进度
canvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint);

}
}
}

activity_main.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">


<com.yongf.circleprogressview.CircleProgressView
android:id="@+id/cpv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" " />

</RelativeLayout>

MainActivity.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.yongf.circleprogressview;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final CircleProgressView cpv = (CircleProgressView) findViewById(R.id.cpv);
cpv.setDesc("下载");
cpv.setIcon(R.drawable.ic_pause);

cpv.setProgressEnable(true);
cpv.setMax(100);

cpv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AsyncTask<Void, Integer, Void>() {
int i = 0;

@Override
protected Void doInBackground(Void... params) {
while (true) {
publishProgress(i);
SystemClock.sleep(100);
if (i >= 100) {
break;
}
i++;
}
return null;
}

@Override
protected void onProgressUpdate(Integer... values) {
Integer value = values[0];
cpv.setProgress(i);
cpv.setDesc(i + "%");
}
}.execute();
}
});
}
}

感谢

感谢访问我的个人博客的朋友,如果您感觉本站对您搜索的问题有所帮助,并感觉对本站还满意的话,顶一下吧,希望您把本站分享给您的朋友!在此对您表示由衷的谢意! :)