自定义view(二)
这里是自定义view(二),上一篇关于自定义view的一些基本知识,比如说自定义view的步骤、会涉及到哪些函数以及如何实现自定义属性,同时实现了一个很基础的自定义控件,一个自定义的计时器,需要看的人可以点击这个链接:http://www.cnblogs.com/YaoJianXun/p/5806926.html。
这次讲的是如何通过坐标系的变化实现一些更复杂的自定义view绘制,上一次博客我们实现了一个类似于计时器的环形控件,这次我们在那个基础上再做一次改动,通过坐标系的变动实现下面的效果:

这里想讲一下关于android坐标系的一些东西:
1、android 坐标系
在android中有两种常用坐标系:
1.1 android坐标系
android坐标系就是以屏幕左上方为原点,向右为x轴正方向,向下为y轴正方的坐标系,可以使用getLocationOnScreen(intlocation[])这个函数获取Android坐标系中点的位置,可就是视图左上角在android坐标系中的位置。
1.2 视图坐标系
这个坐标系描述的是子视图在父视图中的位置,就是子视图左上角在父视图总的位置,坐标系的原点在父视图的左上角,向右为x轴正方向,向下为y轴正方向。
1.3 坐标系常用函数
- view的方法:
getTop():获取到的是view自身顶边到期父布局顶边的距离。
getLeft():获取到的是view自身的左边到其父布局左边的距离。
getBottom(),getRight()也同上,获取的分别是view自身下边右边到其父布局下边右边的距离。
- MotionEvent的方法:
getX():获取点击事件距离控件左边的距离,视图坐标。
getY():获取点击事件距离控件上边的距离,视图坐标。
getRawX(),getRawY(),同上,只是他们获取的android坐标系中的距离,绝对坐标。
1.4 通过坐标系移动实现view绘制
这里介绍两个函数:
- translate():平移android坐标系
- rotate():旋转android坐标系
分析上面图中的效果如何实现:
- 外围的圆形
这个就不做讲述了,很容易实现的效果。
- 表盘上的刻度
这个就要分析一下了,首先画出12点的刻度很容,由于它是一条竖直的直线,只需要指定起止点就可以直接绘制出来了。那么其他的刻度呢,起止点就没有那么容易计算得到了,那么怎么办呢,这个时候其实只要将android坐标系以原点为中心旋转一定的角度,在绘制和12点方向一样的线,就可以了,只不过刻度不同,可能线的长度不同,这个需要设置条件语句进行具体判断,但是绘制的方向很容易就得出来了。下面是代码:
for (int i = 0; i < 60; i++) {
//通过旋转坐标系绘制刻度
String degree = String.valueOf(i / 5);
if (i % 15 == 0) {
mPaint2.setStrokeWidth(5);
mPaint2.setTextSize(30);
canvas.drawLine(mCircleXY, 20, mCircleXY, 80, mPaint2);
if (i == 0) {
canvas.drawText("12", mCircleXY - mPaint2.measureText(degree) / 2, 120, mPaint2);
} else {
canvas.drawText(degree, mCircleXY - mPaint2.measureText(degree) / 2, 120, mPaint2);
}
} else if (i % 5 == 0) {
mPaint2.setStrokeWidth(5);
mPaint2.setTextSize(30);
canvas.drawLine(mCircleXY, 20, mCircleXY,60, mPaint2);
canvas.drawText(degree, mCircleXY - mPaint2.measureText(degree) / 2, 100, mPaint2);
} else {
mPaint2.setStrokeWidth(5);
mPaint2.setTextSize(30);
canvas.drawLine(mCircleXY, 20, mCircleXY, 40, mPaint2);
}
canvas.rotate(6, mCircleXY, mCircleXY);
}
通过上面的代码也能看出,每次选择6度一共旋转60次,每次绘制线的时候判断一下,如果现在整点数,绘制的线长度长一点,如果是12点、3点、6点、9点绘制的线的长度要更长一点。
- 绘制时针分针
这个就更简单了,通过translate()函数移动android坐标系原点到表盘中间,在从中间画出两条长短不一的线就可以了。同时没过一秒,选择一定角度就可以了。下面是代码:
//平移坐标系,绘制时针
canvas.translate(mCircleXY, mCircleXY);
canvas.drawLine(0, 0, 100, 100, mPaint3); //旋转坐标系,绘制分针
canvas.rotate(6 * time, 0, 0);
canvas.drawLine(0, 0, 100, 200, mPaint4); time++;
postInvalidateDelayed(1000);
下面是完整的全部代码:
public class CustomView extends View {
private float mCircleXY, mLength, mRadius;
private Paint mPaint1 = new Paint(); //表圆弧
private Paint mPaint2 = new Paint(); //表刻度
private Paint mPaint3 = new Paint(); //表时针
private Paint mPaint4 = new Paint(); //表秒针
private WindowManager mWM;
private int time = 0;
private int hour = 0;
public CustomView(Context context) {
super(context);
mPaint1.setStyle(Paint.Style.STROKE);
mPaint1.setStrokeWidth(5);
mPaint1.setAntiAlias(false);
mPaint3.setStrokeWidth(20);
mPaint4.setStrokeWidth(10);
setValues();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint1.setStyle(Paint.Style.STROKE);
mPaint1.setStrokeWidth(5);
mPaint1.setAntiAlias(false);
mPaint3.setStrokeWidth(20);
mPaint4.setStrokeWidth(10);
setValues();
}
private void setValues() {
mWM = (WindowManager) getContext()
.getSystemService(Context.WINDOW_SERVICE);
mLength = mWM.getDefaultDisplay().getWidth();
mCircleXY = mLength / 2;
mRadius = (float) (mLength * 0.5);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制钟表外圈圆环
canvas.drawCircle(mCircleXY, mCircleXY, mRadius-20, mPaint1);
//消除锯齿
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG));
for (int i = 0; i < 60; i++) {
//通过旋转坐标系绘制刻度
String degree = String.valueOf(i / 5);
if (i % 15 == 0) {
mPaint2.setStrokeWidth(5);
mPaint2.setTextSize(30);
canvas.drawLine(mCircleXY, 20, mCircleXY, 80, mPaint2);
if (i == 0) {
canvas.drawText("12", mCircleXY - mPaint2.measureText(degree) / 2, 120, mPaint2);
} else {
canvas.drawText(degree, mCircleXY - mPaint2.measureText(degree) / 2, 120, mPaint2);
}
} else if (i % 5 == 0) {
mPaint2.setStrokeWidth(5);
mPaint2.setTextSize(30);
canvas.drawLine(mCircleXY, 20, mCircleXY,60, mPaint2);
canvas.drawText(degree, mCircleXY - mPaint2.measureText(degree) / 2, 100, mPaint2);
} else {
mPaint2.setStrokeWidth(5);
mPaint2.setTextSize(30);
canvas.drawLine(mCircleXY, 20, mCircleXY, 40, mPaint2);
}
canvas.rotate(6, mCircleXY, mCircleXY);
}
//平移坐标系,绘制时针
canvas.translate(mCircleXY, mCircleXY);
canvas.drawLine(0, 0, 100, 100, mPaint3);
//旋转坐标系,绘制分针
canvas.rotate(6 * time, 0, 0);
canvas.drawLine(0, 0, 100, 200, mPaint4);
time++;
postInvalidateDelayed(1000);
}
}
这样就可以绘制出图中所示的表盘,源码的链接:https://github.com/jiushi555/CustomView/tree/master/CustomTimepiece。
转载请标明出处。
不是闷骚的程序员算不上程序员。我的微信公众号“那点鼻事”,在这里周一到周五每天一篇文章,与技术无关,只哈牛逼。

自定义view(二)的更多相关文章
- 自定义view(二)
1.View 的绘制 通过继承View 并重写它的onDraw()来完成绘制. onDraw()有一个参数,就是Canvas对象.使用这个Canvas就可以绘制图像了,Canvas canvas = ...
- Android自定义View (二) 进阶
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自定义View之旅,前面已经介绍过一个自定义View的基础的例 ...
- 自定义View(二)--继承自ViewGroup
自定义View包括很多种,上一次随笔中的那一种是完全继承自View,这次写的这个小Demo是继承自ViewGroup的,主要是将自定义View继承自ViewGroup的这个流程来梳理一下,这次的Dem ...
- Android 自定义View (二) 进阶
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自定义View之旅,前面已经介绍过一个自定义View的基础的例 ...
- 自定义View(二),强大的Canvas
本文转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android中使用图形处理引擎,2D部分是 ...
- Android 自定义View二(深入了解自定义属性attrs.xml)
1.为什么要自定义属性 要使用属性,首先这个属性应该存在,所以如果我们要使用自己的属性,必须要先把他定义出来才能使用.但我们平时在写布局文件的时候好像没有自己定义属性,但我们照样可以用很多属性,这是为 ...
- Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解
Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...
- Android自定义View(二)
前言 魅族手机的闹钟应用中有个倒计时,这个控件还是蛮有趣的.左边是魅族闹钟,右边是我们最终实现的效果,虽然有些细节还需优化,不过基本上已经达到了想要的效果,我们先来就来看看如何实现吧. 分析 确定宽高 ...
- 【朝花夕拾】Android自定义View篇之(二)Canvas常用功能
前言 转在请申明,转自[https://www.cnblogs.com/andy-songwei/p/10960012.html],谢谢! 上一篇讲View的绘制流程中讲到过,最后一步是draw流程, ...
随机推荐
- Win10 的虛擬桌面
Win10 的虛擬桌面我覺得蠻多餘的,平常很少用,除非是像以前的 "切換老闆鍵" ,老闆來了,你不想讓他知道你在幹嘛,趕快切換另外一個桌面. 切換工作視窗:Alt + Tab 叫出 ...
- zabbix3.0.4 部署History
[root@zabbix-Test ~]# history 1 passwd root 2 exit 3 yum install ntpd* 4 yum inst ...
- Chrome 出现adobe flash is out of date的解决方法
最近使用安装了ubuntu和linux mint,都发现firefox的flash虽然能用,但还是觉得有点小问题,想使用google chrome,但无奈,一安装使用后就发现flash不能用,显示ad ...
- AngularJS最理想开发工具WebStorm
http://blog.fens.me/angularjs-webstorm-ide/ Angularjs插件下载地址:http://plugins.jetbrains.com/plugin/6971 ...
- AdapterViewFlipper的功能和用法
AdapterView继承了AdapterViewAnimator,它也会显示Adapter提供的多个View组件,但每次只能显示一个View组件,程序可通过showPrevious和showNext ...
- Java线程:锁
一.锁的原理 Java中每个对象都有一个内置锁,当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行的代码类的当前实例(this实例)有关的锁.获得一个对象的锁也称为获取锁.锁 ...
- cookie、session、sessionid的区别
我们都知道银行,银行的收柜台每天要接待客户存款/取款业务,可以有几种方案: 1.凭借柜台职员的记忆,由收柜台职员来为每位顾客办理存款/取款业务,单凭职员的记忆力,要记到每位顾客的相貌,并迅速这个顾客当 ...
- 使用AIR进行移动APP开发常见功能和问题(上)
1. 获取最近联系人 思路:侦听Geolocation的update事件,获取经度和纬度信息,再把坐标信息上传至服务器,服务器比较坐标信息算出距离,返回最近位置的若干个人. update时间在2种情 ...
- 我为什么不看好微信小程序
我自认为对新技术还是比较有热情的,可对于小程序这个“新技术”,我却完全是被动的.去年9月份的时候,微信小程序开始内测,瞬间引爆朋友圈.知乎等一众分享平台.当时我大概了解了一下,觉得从技术角度上来说没啥 ...
- CodeForces 333A
Secrets Time Limit:1000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Submit Sta ...