先看效果图吧

我们要实现一个自定义的再一个圆形中绘制一个弧形的自定义View,思路是这样的:

  先要创建一个类ProgressView,继承自View类,然后重写其中的两个构造方法,一个是一个参数的,一个是两个参数的,因为我们要在xml文件中使用该自定义控件,所以必须要定义这个两个参数的构造函数。创建完了这个类后,我们先不去管它,先考虑我们实现的这个自定义View,我们想让它的哪些部分可以由使用者自己指定,比如说这个Demo中我们让他的外面圆的外边框颜色和宽度,还有扇形部分的颜色,扇形增长的速度等等属性,这时候我们要在项目工程目录的res/values目录下创建一个资源文件命名为attrs(注意,名字随意,只是大多数情况下都这么叫而已),然后我们在这个资源文件中添加我们想要的属性,如下:

 <?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ProgressView">
<!--circleColor 设置圆形边框的颜色 sweepColor设置扇形变换的颜色
startAngle 设置起始角度 sweepStep 设置变换的步长-->
<attr name="circleColor" format="color|reference"></attr>
<attr name="sweepColor" format="color|reference"></attr>
<attr name="startAngle" format="integer"></attr>
<attr name="sweepStep" format="integer"></attr>
<attr name="padding" format="integer"></attr>
</declare-styleable>
</resources>

可以看到,<declare-styleable>标签中的name属性是为了方便我们获取AttributeSet时候使用,而<attr>标签中name,则是我们希望控件可以自定义的属性部分,类似于xml文件中的android:name=""等标签的使用。format属性是设置该属性可以接受什么类型的参数。

定义好了自定义资源类,我们开始写ProgressView中的主要代码:

 package com.yztc.customprogressview;

 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.util.AttributeSet;
import android.view.View; /**
* 自定义的
*/
public class ProgressView extends View {
private int sweepStep = 10;//扇形变换的步长(就是角度)
private int padding = 40;//外边框距离扇形的距离 填充
private int circleColor = Color.GRAY;//边框的颜色
private int sweepColor = Color.BLUE;//扇形颜色
private int startAngle = 90;//起始角度
//设置外边框圆的边框粗细
private int storke = 20; private int sweepAngle = 0;//扫过的角度 private static final int DEFAULT_WIDTH = 200;
private static final int DEFAULT_HEIGHT = 200; public ProgressView(Context context) {
super(context);
} //如果要在xml文件中使用该自定义控件,则必须重写两个参数的构造函数
//因为我们使用自定义的属性的时候,会默认传递过来一个AttributeSet集合
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ProgressView);
if (array != null) {
//获取我们在xml中设置的各个自定义属性
sweepStep = array.getInteger(R.styleable.ProgressView_sweepStep, sweepStep);
padding = array.getInteger(R.styleable.ProgressView_padding, padding);
circleColor = array.getColor(R.styleable.ProgressView_circleColor, circleColor);
sweepColor = array.getColor(R.styleable.ProgressView_sweepColor, sweepColor);
startAngle = array.getInteger(R.styleable.ProgressView_startAngle, startAngle); //回收TypeArray资源
array.recycle();
}
} /**
* 先绘制外边框 --内部扇形
*
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
Paint mPaint = new Paint();
mPaint.setAntiAlias(true); //设置抗锯齿
//绘制外层的圆框
mPaint.setColor(circleColor);
mPaint.setStrokeWidth(storke);
mPaint.setStyle(Paint.Style.STROKE);//设置圆形为空心的圆
//这里我们得到控件的Height和Width,根据Heigh和Width来确定圆心的位置,来绘制外层圆
canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2 - storke / 2, mPaint);
// Log.d("tag", "onDraw: "+getWidth());
invalidate();//请求重新绘制view //绘制内部的扇形
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(sweepColor);
/*
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)
RectF oval 指定扇形的矩形容器对象 指定圆弧的外轮廓的矩形
float startAngle 表示圆弧的起始角度
float sweepAngle 表示圆弧走过扫过的角度 顺时针方向
boolean useCenter 如果设置为true 在绘制圆弧时将圆心包括在内,是指以一个固定的圆心来绘制弧形(扇形),
如果指定为false,则不规则绘制扇形
Paint paint 画笔 颜色 填充 public RectF(float left, float top, float right, float bottom)
float left 矩形的左边点(左切点)的x坐标
float top 矩形上边点(上切点)的y轴坐标
float right, 矩形的右边点(右切点)的x坐标
float bottom 矩形的下边点(下切点)的y坐标
*/
//RectF中的四个参数,分别对应其内切圆的四个切点的坐标
RectF rectF = new RectF(padding + storke, padding + storke, getWidth() - padding - storke, getWidth() - padding - storke);
canvas.drawArc(rectF, startAngle, sweepAngle, true, mPaint); sweepAngle += sweepStep;//根据步长更新扫过的角度
sweepAngle = sweepAngle > 360 ? 0 : sweepAngle;
invalidate();//重绘view
} //因为我们是继承的View来自定义的View,所以onMeasure()方法要重写
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int wMode = MeasureSpec.getMode(widthMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
int wSize = MeasureSpec.getSize(widthMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec); //因为绘制的是圆,所以判断一下高度或者宽度中的一个就可以。
switch (wMode) {
case MeasureSpec.AT_MOST://android:layout_width="warp_content"
//获取屏幕像素
float density = getResources().getDisplayMetrics().density;
wSize = (int) (DEFAULT_WIDTH * density);
hSize = (int) (DEFAULT_HEIGHT * density);
break;
//当在xml中指定控件的宽高为match_parent或者指定数值的宽高时,回调以下代码
case MeasureSpec.EXACTLY://android:layout_width="match_parent" android:layout_width="40dp"
wSize = hSize = Math.min(wSize, hSize);
break;
}
//只要重写onMeasure()方法,一定要调用以下方法,不然会报错
setMeasuredDimension(wSize, hSize);
}
}

我们先画一个外部的圆,也就是都用drawCircle()方法,这里我们调用getWidth(),getHeight()表示得到布局中设置的控件的尺寸,因为是圆,所以可以使用getWidth()/2来表示圆心位置。而画内部弧形的时候,确定其圆心位置,左部点的坐标是外面圆的边框加上弧形与原的间距padding来确定,右侧点的x坐标则是getWidth()得到总长度,减去边框宽度,再减去padding得到,上边距和下边距同样,不明白的画一个图立马明白。大部分不好理解的地方都有注释,只要认真看不会看不明白的~

然后就是在布局中引入我们的自定义View了:

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
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="com.yztc.customprogressview.MainActivity"> <com.yztc.customprogressview.ProgressView
android:id="@+id/pv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0000ff"
app:padding="20"
app:circleColor="#aa0000"
app:sweepColor="#00aa00"
app:sweepStep="1"
app:startAngle="180"
/>
</RelativeLayout>

需要注意的是我们需要在布局的跟标签下面加上这么一段代码:xmlns:app="http://schemas.android.com/apk/res-auto"

用来指定我们可以使用自己再attrs中自定义的属性啦~,使用的形式就是app:你定义的属性。当然,这个app也不是固定的写法,只要跟上面你加的那段代码的xmlns后面的字段一致就可以了~

还有需要注意的是:

默认使用Canvas类的drawCircle()方法来画圆的时候,圆的半径是你指定的半径,再加上一半的边长,比如你的边框size=10,radius=50,则实际空心部分的半径为55.注意这点,否则画出来的圆的四个切点位置会与其他位置有些不一样,类似出现锯齿的效果。具体请看drawCircle()的Rect边框问题

自定义View--一个简单地圆形Progress效果的更多相关文章

  1. python+selenium之自定义封装一个简单的Log类

    python+selenium之自定义封装一个简单的Log类 一. 问题分析: 我们需要封装一个简单的日志类,主要有以下内容: 1. 生成的日志文件格式是 年月日时分秒.log 2. 生成的xxx.l ...

  2. Python+Selenium中级篇之8-Python自定义封装一个简单的Log类《转载》

    Python+Selenium中级篇之8-Python自定义封装一个简单的Log类: https://blog.csdn.net/u011541946/article/details/70198676

  3. Android 自定义View修炼-Android实现圆形、圆角和椭圆自定义图片View(使用BitmapShader图形渲染方法)

    一.概述 Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的.实现圆角图片的方法其实不少,常见的就是利用Xfermode,Shader.本文直接继 ...

  4. Android -- 自定义view实现keep欢迎页倒计时效果

    1,最近打开keep的app的时候,发现它的欢迎页面的倒计时效果还不错,所以打算自己来写写,然后就有了这篇文章. 2,还是老规矩,先看一下我们今天实现的效果 相较于我们常见的倒计时,这次实现的效果是多 ...

  5. Python之自定义封装一个简单的Log类

    参考:http://www.jb51.net/article/42626.htm 参考:http://blog.csdn.net/u011541946/article/details/70198676 ...

  6. 自定义View绘制简单的圆环的实现

    package com.loaderman.mywave; import android.content.Context; import android.graphics.Canvas; import ...

  7. 自定义View(1)简单流程及示例模板

    1,继承View , ViewGroup,或TextView等等 2,绘制相关的api, canvas 画布, paint 画笔 2,重写重要的函数(注意这个顺序) onMeasure 属于View的 ...

  8. android自定义view仿照MIUI中音量控制效果

    先看效果图: 这就是miui中的音量效果图,实现思路是自定义视图,绘制圆环,然后设置进度显示. 核心代码在onDraw中实现如下: @Override protected void onDraw(Ca ...

  9. 一个简单的tr:hover效果

    昨天,搞项目的时候,在一个小问题上卡了40分钟,现在想想,还是平时比较少去注意一些细节,经过这次,一定要去多注意细节了. 好了废话不多说,我现在说明下遇到的问题,一个表格中,要求是当鼠标滑过每一行时, ...

随机推荐

  1. Ubuntu rsync同步

    >服务器端:Ubuntu 9.10 - 192.168.1.3客户端:Ubuntu 10.04 - 192.168.1.73 我们先来设置一下服务器端的配置 1.ubuntu系统安装完之后,rs ...

  2. QQ群共享文件下载很慢解决办法

    QQ群共享文件下载很慢解决办法.我们经常会不群里面共享文件,文件文件稍大,下载非常慢.家庭是20M的网速,一般正常下载能够达到2.5MB左右,而在QQ群实际下载网速却只有80KB左右.如果要下1G,就 ...

  3. C#中检测某个类(方法、程序集等各种部分)是否应用了指定的特性以及对特性的一些简单操作

    前言:不管是自定义的一些特性,或者是C#中内置的特性,均继承自Attribute这个类,这个类也提供了一些方法,方便我们使用. Attribute类有三个静态方法:1.IsDefined,如果有指定的 ...

  4. CentOS查看内核版本,位数,版本号

    1)[root@localhost ~]# cat /proc/version Linux version 2.6.18-194.el5 (mockbuild@builder10.CentOS.org ...

  5. wamp集成环境开启虚拟主机多站点功能

    方法/步骤   如果不是全白色,说明没有正常启动,先解决这个情况再进行下一步操作. 我们一键安装wamp到D盘,并可以正常启动,状态如下图所示:   在D:\wamp\bin\apache\Apach ...

  6. C# winform窗体假死

    C#  winform窗体假死 我们经常会遇到当执行一个比较大的函数时,窗体会出现假死的现象,给用户的体验不是很好,于是我们遇到了问题,那么就必须解决,我们该如何解决呢,首先在自己的脑里画个问号,接下 ...

  7. Win API 内存整理

    记得我的笔记本上曾经安装了一款名为内存整理大师的软件,当时觉得挺好用而且挺NB的,就是导致开机启动有点慢. 当时我就在想,内存整理是怎么实现的?不过那是水平实在是不怎么样,估计连windows程序的消 ...

  8. Codecademy For Python学习笔记

    一.Python Lists and Dictionaries: 1. 2.

  9. testNG中@Factory详解

    @Factory注解从字面意思上来讲就是采用工厂的方法来创建测试数据并配合完成测试,其主要应对的场景是:对于某一个测试用例或方法,我们需要输入多个测试数据进行测试,并且这些测试数据可以是有一定关系(可 ...

  10. 正则表达式验证工具类RegexUtils.java

    Java 表单注册常用正则表达式验证工具类,常用正则表达式大集合. 1. 电话号码 2. 邮编 3. QQ 4. E-mail 5. 手机号码 6. URL 7. 是否为数字 8. 是否为中文 9. ...