自定义View--一个简单地圆形Progress效果
先看效果图吧
我们要实现一个自定义的再一个圆形中绘制一个弧形的自定义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效果的更多相关文章
- python+selenium之自定义封装一个简单的Log类
python+selenium之自定义封装一个简单的Log类 一. 问题分析: 我们需要封装一个简单的日志类,主要有以下内容: 1. 生成的日志文件格式是 年月日时分秒.log 2. 生成的xxx.l ...
- Python+Selenium中级篇之8-Python自定义封装一个简单的Log类《转载》
Python+Selenium中级篇之8-Python自定义封装一个简单的Log类: https://blog.csdn.net/u011541946/article/details/70198676
- Android 自定义View修炼-Android实现圆形、圆角和椭圆自定义图片View(使用BitmapShader图形渲染方法)
一.概述 Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的.实现圆角图片的方法其实不少,常见的就是利用Xfermode,Shader.本文直接继 ...
- Android -- 自定义view实现keep欢迎页倒计时效果
1,最近打开keep的app的时候,发现它的欢迎页面的倒计时效果还不错,所以打算自己来写写,然后就有了这篇文章. 2,还是老规矩,先看一下我们今天实现的效果 相较于我们常见的倒计时,这次实现的效果是多 ...
- Python之自定义封装一个简单的Log类
参考:http://www.jb51.net/article/42626.htm 参考:http://blog.csdn.net/u011541946/article/details/70198676 ...
- 自定义View绘制简单的圆环的实现
package com.loaderman.mywave; import android.content.Context; import android.graphics.Canvas; import ...
- 自定义View(1)简单流程及示例模板
1,继承View , ViewGroup,或TextView等等 2,绘制相关的api, canvas 画布, paint 画笔 2,重写重要的函数(注意这个顺序) onMeasure 属于View的 ...
- android自定义view仿照MIUI中音量控制效果
先看效果图: 这就是miui中的音量效果图,实现思路是自定义视图,绘制圆环,然后设置进度显示. 核心代码在onDraw中实现如下: @Override protected void onDraw(Ca ...
- 一个简单的tr:hover效果
昨天,搞项目的时候,在一个小问题上卡了40分钟,现在想想,还是平时比较少去注意一些细节,经过这次,一定要去多注意细节了. 好了废话不多说,我现在说明下遇到的问题,一个表格中,要求是当鼠标滑过每一行时, ...
随机推荐
- TASK_INTERRUPTIBLE 和TASK_UNINTERRUPTIBLE
TASK_INTERRUPTIBLE 和TASK_UNINTERRUPTIBLE TASK_INTERRUPTIBLE 和TASK_UNINTERRUPTIBLE 的区别 TASK_INTERRUPT ...
- Zabbix监控解决方案
思通运维监控主要用来监控IT 基础设施组件的可用性和性能.监控项目是不受限制的,并且可以对IT 基础设施健康状态进行复杂分析.通过确定IT 系统问题的“来源”,使用户快速响应故障来降低宕机成本. 网络 ...
- Netty4.x中文教程系列(三) Hello World !详解
Netty 中文教程 (二) Hello World !详解 上一篇文章,笔者提供了一个Hello World 的Netty示例. 时间过去了这么久,准备解释一下示例代码. 1.HelloServer ...
- DeepLearning常用库简要介绍与对比
网上近日流传一张DL相关库在Github上的受关注度对比(数据应该是2016/03/15左右统计的): 其中tensorflow,caffe,keras和Theano排名比较靠前. 今日组会报告上tj ...
- C# 读取指定URL的内容
#region 读取指定URL的内容 /// <summary> /// 读取指定URL的内容 /// </summary> /// <param name=" ...
- [原]1856-More is better-基础并查集
思路:注意n为0的时候输出1,还有内存.这题是数据水了,要不我的Count[ ]数组,开10^5绝对会WA.离散化还没想清楚,想清楚了再更新代码.[水过代码下面是正经的AC代码,其实这道题不用离散化, ...
- IO(一)
文件相关 package com.bjsxt.io.file; import java.io.File; /** * 两个常量 * 1.路径分隔符 ; * 2.名称分隔符 /(windows) /(l ...
- CString和string
CString和string(一) 概述 string和CString均是字符串模板类,string为标准模板类(STL)定义的字符串类,已经纳入C++标准之中: CString(typedef CS ...
- Open Explorer Plugin for Eclipse (eclipse 插件 在eclipse里面打开文件目录)
就是在eclipse里面直接打开文件所在的目录地址 只要将下面的jar 文件放到你的 “$ECLIPSE_HOME/plugins” 下面,重启eclipse就ok了 要想卸载的话 停止eclip ...
- HDU 2686 (双线程) Matrix
这也是当初卡了很久的一道题 题意:从左上角的格子出发选一条路径到右上角然后再回到左上角,而且两条路径除了起点和终点不能有重合的点.问所经过的格子中的最大和是多少 状态设计:我们可以认为是从左上角出发了 ...