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中的原点坐 ...
随机推荐
- 一个MySQL双引号把我坑惨了!
一.前言 最近经常碰到开发误删除误更新数据,这不,他们又给我找了个麻烦,我们来看下整个过程,把我坑得够惨. 二.过程 由于开发需要在生产环节中修复数据,需要执行120条SQL语句,需要将数据进行更新, ...
- tomcat反向代理,监控,性能优化详细步骤
第1章 tomcat简介Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由Apache,Sun和其他一些公司及个人共同 ...
- Centos7 更换yum软件源
https://blog.csdn.net/zhinian1204/article/details/123975403
- 7.项目结构的构建和提交到gitee
创建微服务模块 以商城项目的产品模块为例 点击Next,然后倒入依赖的包,Spring Web 然后在选择一个微服务和微服务之间调用需要的包:OpenFeign 导入这两个微服务的组件就行,后面需要用 ...
- java8 stream流的使用
List<Paper> list = new ArrayList<>();list.add(new Paper("m",2L));list.add(new ...
- 从零搭建php环境-php8-扩展-redis
一.下载1.https://pecl.php.net/get/redis-5.3.2.tgz下载到本地,文件传输上传到 /usr/local/src/2.wget -P /usr/local/src/ ...
- Docker学习——多阶段构建(六)
之前的做法 在 Docker 17.05 版本之前,我们构建 Docker 镜像时,通常会采用两种方式: 全部放入一个 Dockerfile 一种方式是将所有的构建过程编包含在一个 Dockerfil ...
- zabbix监控mysql数据库——qps和tps
首先可以继续顺着zabbix监控mysql继续往下做 1.首先在42的继续编写qps和tps 1.1qps 在41服务端查询: 1.2 tps 2.在web进行查看
- Check If Binary Tree Is Completed
Check if a given binary tree is completed. A complete binary tree is one in which every level of the ...
- 训练题——DS18B20部分
Author:Cherry_Ywj 0. 前言 本文档以 DS18B20 为例,主要介绍如何针对一种传感器编写相应的驱动库,驱动是单片机开发中难度较大的一环.从看别人代码并对照 datasheet 开 ...