先看效果图吧

我们要实现一个自定义的再一个圆形中绘制一个弧形的自定义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. jqGrid中实现radiobutton的两种做法

    http://blog.sina.com.cn/s/blog_4f925fc30102e27j.html   jqGrid中实现radiobutton的两种做法 ------------------- ...

  2. for (Map.Entry<Long, Integer> me : zlSendMap.entrySet())

    public static void main(String[] args) throws IOException { Map<String,String> map = new HashM ...

  3. [转]应聘Java,jsp,j2ee软件工程师笔试中可能出现的问题

    相信大家应聘的时候第一关就是笔试,即使是一位很有经验的工程师也不一定能够顺利通过,笔试不好,可能就无法进行面试,即使能够进行面试,考官对你的印象也不会很好,问的问题也会很多,估计很难吃的消,当然如果你 ...

  4. HTML5的fieldset标签

    定义和用法 fieldset 元素可将表单内的相关元素分组,绘制一个带标题的框,有如winform开发中的panel. <fieldset> 标签将表单内容的一部分打包,生成一组相关表单的 ...

  5. C 语言文件操作

    C 语言文件操作 1. 数据流:     程序与数据的交互以流的形式进行.fopen 即打开数据流,fclose 即刷新数据流.     所谓数据流,是一种抽象,表示这段数据像流一样,需要逐步接收,不 ...

  6. KVM/QEMU桥接网络设置及kvm资料

    KVM/QEMU桥接网络设置 配置kvm的网络有2种方法.其一,默认方式为用户模式网络(Usermode Networking),数据包由NAT方式通过主机的接口进行传送.其二,使用桥接方式(Brid ...

  7. [HIHO1039]字符消除(字符串,枚举,模拟)

    题目链接:http://hihocoder.com/problemset/problem/1039 思路:枚举所有字符更新的位置和ABC三种修改方案,之后再模拟消除规则,一步一步去消除.直到无法消除, ...

  8. 在DirectX 中进行2D渲染

    http://flcstudio.blog.163.com/blog/static/756035392008115111123672/ 最近,我看到很多关于DirectX8在最新的API中摒弃Dire ...

  9. 基础组件_Window(窗口)

    窗口控件是一个浮动和可拖拽的面板可以用作应用程序窗口.默认情况下,窗口可以移动,调整大小和关闭.它的内容也可以被定义为静态html或要么通过ajax动态加载. 1. 通过标签创建窗口

  10. android SDK 更新

    在SDK Manager下Tools->Options打开了SDK Manager的Settings,选中“Force https://… sources to be fetched using ...