一、前言

上节 通过一个简单的旋转环对自定义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 (二)的更多相关文章

  1. Android自定义View (二) 进阶

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自定义View之旅,前面已经介绍过一个自定义View的基础的例 ...

  2. Android 自定义View (二) 进阶

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自定义View之旅,前面已经介绍过一个自定义View的基础的例 ...

  3. Android 自定义View二(深入了解自定义属性attrs.xml)

    1.为什么要自定义属性 要使用属性,首先这个属性应该存在,所以如果我们要使用自己的属性,必须要先把他定义出来才能使用.但我们平时在写布局文件的时候好像没有自己定义属性,但我们照样可以用很多属性,这是为 ...

  4. Android 自定义view(二) —— attr 使用

    前言: attr 在前一篇文章<Android 自定义view -- attr理解>已经简单的进行了介绍和创建,那么这篇文章就来一步步说说attr的简单使用吧 自定义view简单实现步骤 ...

  5. Android 自定义View及其在布局文件中的使用示例(二)

    转载请注明出处 http://www.cnblogs.com/crashmaker/p/3530213.html From crash_coder linguowu linguowu0622@gami ...

  6. Android自定义View(二、深入解析自定义属性)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51468648 本文出自:[openXu的博客] 目录: 为什么要自定义属性 怎样自定义属性 ...

  7. Android 自定义 view(三)—— onDraw 方法理解

    前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...

  8. Android 自定义View及其在布局文件中的使用示例(三):结合Android 4.4.2_r1源码分析onMeasure过程

    转载请注明出处 http://www.cnblogs.com/crashmaker/p/3549365.html From crash_coder linguowu linguowu0622@gami ...

  9. android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

    我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...

  10. Android自定义View研究--View中的原点坐标和XML中布局自定义View时View触摸原点问题

    这里只做个汇总~.~独一无二 文章出处:http://blog.csdn.net/djy1992/article/details/9715047 Android自定义View研究--View中的原点坐 ...

随机推荐

  1. MFC程序运行原理初探

    几年前,写过一段时间的MFC,但是只知其然不知其所以然,最近闲来无事,研究了一下MFC程序的运行顺序,特此记录一下. 首先,如果我们创建一个MFC程序的话,首先会自动生成一个CWinApp的子类,程序 ...

  2. select控件操作汇总

    1.通过select的text来选中对应的option $("#dddddd option:contains('小型车')").attr("selected", ...

  3. Day 22 22.1.1:增量式爬虫 - 场景1的实现

    场景1的实现: 数据指纹: 数据的唯一标识.记录表中可以不直接存储数据本身,直接存储数据指纹更好一些. 创建爬虫爬虫文件: cd project_name(进入项目目录) scrapy genspid ...

  4. string转JSONObject顺序不变和 往map放数据按顺序

    JSONObject field = JSONObject.parseObject(fieldStr,Feature.OrderedField); Map<String,String> m ...

  5. 397. 整数替换 (Medium

    问题描述 397. 整数替换 (Medium) 给定一个正整数 n ,你可以做如下操作: 如果 n 是偶数,则用 n / 2 替换 n. 如果 n 是奇数,则可以用 n + 1 或 n - 1 替换 ...

  6. continue练习

    using System; namespace continue_的练习 { class Program { static void Main(string[] args) { int sum = 0 ...

  7. python max()用法

    起因是看到一道面试题 "统计字符串中出现次数最多的字符,并返回出现次数" 问题很简单,刚开始没思路,只想到了循环统计,但是觉得太蠢了,直到我发现了max()的key用法,果然还是我 ...

  8. Python_DL_July_深度学习_10_深度学习与各种迁移学习应用

    深度学习10(上)深度学习与各种迁移学习应用

  9. JavaScript 字符串的操作

    1. 在指定位置,插入字符串(此需求来源于,img中src没值的字符串标签中,插入图片http地址) // 使用slice写出的 自定义方法,绑定在String的原型链上 String.prototy ...

  10. zabbix监控mysql数据库——qps和tps

    首先可以继续顺着zabbix监控mysql继续往下做 1.首先在42的继续编写qps和tps 1.1qps 在41服务端查询: 1.2 tps 2.在web进行查看