一、前言

上节 通过一个简单的旋转环对自定义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()方法。

最新文章

  1. jpa 表字段转bean对象
  2. Linux 文件rwx权限问题 chmod 777 XXX 任何人拥有最高权限
  3. 指定的参数错误。Vim.Host.DiskPartitionInfo.-spec VSPHERE.LOCAL\Administrator WIN-DOPGQVRRU2C
  4. Bluetooth L2CAP介绍
  5. MySQL的基本数据类型与数据类型优化
  6. 手机淘宝中的那些Web技术-使用了类似PhoneGap的实现
  7. git版本控制 for window安装和命令行使用
  8. C++ opentracing zipkin
  9. python3+selenium框架设计05-配置文件和浏览器引擎类
  10. LeetCode 总结,二叉树各种类型问题小结
  11. instr()函数--支持模糊查询
  12. 使用Maven导出项目依赖的jar包
  13. LG2731 骑马修栅栏 Riding the Fences
  14. LINQ操作符三:限制操作符
  15. 【Android】Could not find XXX.apk!的解决方法
  16. vue生命周期小笔记
  17. 在js里面比较大小必须先转换成number
  18. linux命令汇总1
  19. 【ArcGIS for Android】基于位置查询Graphic和Feature
  20. CentOS6.8编译安装LAMP

热门文章

  1. Telnet登陆网络设备执行命令脚本
  2. lxml库和BeautifulSoup库常用点小结
  3. 解决Ubuntu下的的“system program problem detected”问题
  4. Oracle 存储过程4:PL/SQL动态执行DDL语句
  5. UI设计圈年终福利,错过一次等一年!
  6. Jquery EasyUI dataGrid 修改默认分页大小 不起效果
  7. mysql数据库配置
  8. 哈希表相关题目-python
  9. nodejs发布cesium问题,其他电脑访问发布
  10. 检测sqlserver数据库是否能远程连通