Android 自定义View (二)
一、前言
上节 通过一个简单的旋转环对自定义view作了一个基本的认识,本文将大致讲解下实现的思路以及对该view的一些可能的改进。
二、思路
主要通过重写 view 中的 onDraw() 方法,利用 canvas 类中的 drawArc() 方法绘制圆弧,其中第一个参数 rectF 是一个浮点矩形,确定了圆弧的大小及位置 (想象一个放在矩形中的圆,截取其弧即成圆环)。其中圆弧颜色由画笔类 Paint 定义, 为简单起见,这里使用两种颜色的渐变色。值得一提的是,当圆弧两端成圆头时 ( paint.getStrokeCap() == Paint.Cap.ROUND ),其首端的圆头颜色为尾部的颜色,如图2.1.1 所示。因此此处要将起始旋转角度 + width/2。其中 width 为圆环的宽度,除以2 恰好为圆头的半径,故可以通过这种办法消除掉,如图2.1.2所示
绘制圆弧需要确定起始角度 startAngle,以及扫过的角度sweepAngle,对于 startAngle,其中3点钟方向为0°, sweepAngle一般不超过360° (超过即成一个完整的圆)。此外还需要一个boolean变量的值,来确定是否绘出圆弧对应的半径。由于我们不需要扇形,这里设为fasle。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.rotate(angle, centerX, centerY);
canvas.drawArc(rectF, paint.getStrokeCap() == Paint.Cap.ROUND ? startAngle + width/2f: startAngle,
sweepAngle, false, paint);
}

图2.1.1 首部圆头部分出现尾部颜色 图2.1.2 正常的圆弧
canvas.drawArc() 的第五个参数为Paint类型,这里定义了绘制圆弧所用到的画笔,如下所示
private void setPaint(){
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setShader(new SweepGradient(centerX, centerY,
new int[]{startColor, endColor},
new float[]{startAngle/360f*1.0f, sweepAngle/360f*1.0f}));
paint.setAntiAlias(true);
paint.setStrokeWidth(width);
}
此处主要说说何处初始化该 paint 的原因。由于实现圆弧的渐变色用到了 SweepGradient 着色器,着色器需要传入x、y来确定扫描渐变色的中心,故需要在获取到控件中心之后再进行初始化。在该自定义圆弧控件中,是通过 onSizeChanged(int w, int h, int oldw, int oldh) 方法来获取控件视图的中点,故在 onSizeChanged() 方法中对画笔进行初始化,如下所示
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerX = w / 2;
centerY = h / 2;
rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
setPaint();
}
最后,通过 ValueAnimator 类给圆弧设置一个旋转动画,通过调用视图本身的 invalidate() 方法,不断通知视图进行重绘 (不断调用onDraw()方法 ),实现了圆弧视觉上的旋转。
public void startAnim(){
final ValueAnimator animator = ValueAnimator.ofInt(0,360);
animator.setDuration(duration);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
angle = (int) animation.getAnimatedValue();
invalidate();
}
});
animator.start();
}
下节 讲述如何添加自定义属性,在xml中声明旋转环的颜色、半径、宽度,旋转速率等,避免在代码中显式调用setXXX()方法。
Android 自定义View (二)的更多相关文章
- Android自定义View (二) 进阶
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自定义View之旅,前面已经介绍过一个自定义View的基础的例 ...
- Android 自定义View (二) 进阶
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自定义View之旅,前面已经介绍过一个自定义View的基础的例 ...
- Android 自定义View二(深入了解自定义属性attrs.xml)
1.为什么要自定义属性 要使用属性,首先这个属性应该存在,所以如果我们要使用自己的属性,必须要先把他定义出来才能使用.但我们平时在写布局文件的时候好像没有自己定义属性,但我们照样可以用很多属性,这是为 ...
- Android 自定义view(二) —— attr 使用
前言: attr 在前一篇文章<Android 自定义view -- attr理解>已经简单的进行了介绍和创建,那么这篇文章就来一步步说说attr的简单使用吧 自定义view简单实现步骤 ...
- Android 自定义View及其在布局文件中的使用示例(二)
转载请注明出处 http://www.cnblogs.com/crashmaker/p/3530213.html From crash_coder linguowu linguowu0622@gami ...
- Android自定义View(二、深入解析自定义属性)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51468648 本文出自:[openXu的博客] 目录: 为什么要自定义属性 怎样自定义属性 ...
- Android 自定义 view(三)—— onDraw 方法理解
前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...
- Android 自定义View及其在布局文件中的使用示例(三):结合Android 4.4.2_r1源码分析onMeasure过程
转载请注明出处 http://www.cnblogs.com/crashmaker/p/3549365.html From crash_coder linguowu linguowu0622@gami ...
- android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索
我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...
- Android自定义View研究--View中的原点坐标和XML中布局自定义View时View触摸原点问题
这里只做个汇总~.~独一无二 文章出处:http://blog.csdn.net/djy1992/article/details/9715047 Android自定义View研究--View中的原点坐 ...
随机推荐
- Vulnhub 靶场 CORROSION: 2
Vulnhub 靶场 CORROSION: 2 前期准备 下载地址:https://www.vulnhub.com/entry/corrosion-2,745/ 靶机地址:192.168.147.19 ...
- 用xlutils.copy写入中文的问题
用xlutils.copy 将中文写入excel文档中 遇到的问题1: Traceback:Traceback (most recent call last):File "C:\Users\ ...
- vue element-ui form验证中自定义验证方式通过不返回true问题
项目中使用了element-ui的form验证,自定义了手机号的验证规则,验证不通过的时候定义了callback()扔出错误.但是忘了写通过的callback().导致form验证通过拿不到返回的va ...
- vm虚拟机和主机之间互传文件
u盘大家都有吧,用u盘吧,超方便! vmtools 从主机传文件到虚拟机 可以通过之间复制粘贴/拖拽 或者共享文件夹的方式 从虚拟机传文件到主机,查到了说说是要在虚拟机里面改一个什么映射设置,改完之后 ...
- Java实现输出三角形
本来是想实现空心的,想了太久没写出来就算了 代码 package com.qaq.strruct;public class TestDemo01 { //打印三角形 //思路:空格的距离和星星的数量成 ...
- sprinboot多个子模块下 依赖包没有找到 解决方案
最近因为在使用springboot开发项目,在开发过程中,发现自己的子模块导入通用的模块 在启动中 说找不到这个类 百度下 说我要在pom文件下 pulus 插件 那里 加上这段代码 <conf ...
- python torch 解决OSError: [WinError 126] 找不到指定的模块。 Error loading "D:\Anaconda3\lib\site-packages\torch\lib\asmjit.dll" or one of its dependencies.(安装完torch模块后出现找不到指定模块的问题)
昨天安装了一下python的torch模块,然后出现了以下错误: 根据叙述是因为dll文件,后来 经过我的思考...,升级了一下numpy库,就没有问题了. 根据叙述是因为dll文件,后来 经过我的思 ...
- Visual Studio常用的宏
$(SolutionDir) 表示获取解决方案文件.sln所在文件夹 $(ProjectDir 获取项目工程文件.vcxproj所在文件夹 $(Configuration) 获取编译后的Debug / ...
- 在datagridview中首列添加复选框
//为dgv增加复选框列 DataGridViewCheckBoxColumn checkbox = new DataGridViewCheckBoxColumn(); //列显示名称 checkbo ...
- Go 的位操作
在计算机内存昂贵,处理能力有限的美好旧时光里,用比较黑客范的位运算方式去处理信息是首选方式(某些情况下只能如此).时至今日,直接使用位运算仍然是很多计算领域中不可或缺的部分,例如底层系统编程,图形处理 ...