看了题目,大家都该知道,我今天想说些什么了,是的,我今天想说说Canvas这个android中的让人摸不着头脑的元素,对于Canvas很多人都知道他就是用来画东西的,其他的也没啥用,是啊,说的没错,它就是用来画东西的,可能刚接触android的童鞋们不了解,但是有一定时间开发经验的小伙伴们都知道,Canvas是走进android高级开发道路上必不可少的,那么它究竟有什么地方让我们这么捉摸不透呢?下面让我们一点一点的了解——Canvas
为了让大家能够熟悉Canvas,我在接下来的文段落中会教大家绘制一个简单的表盘上的数字,当然,他和表盘一样,有12个数字,而且只画整点时间数,先给大家看一下效果图吧
其实很简单,就是一个背景,上面画了一圈数字,但是大家看好了,数字是正对着大家的,没有任何倾斜,看起来很容易,这需要丰富的想象力啊,否则还真想不出来是怎么实现的
好了,废话就不说了,先给大家说说这个Canvas吧,在Android中我们在写自定义View的时候,大家都知道,有三种方式,一种是继承自View,一种是继承制ViewGroup,还有一种是继承自现有控件,对现有空间进行改造,那么最为灵活的就是继承自View了,当然这也是难点,确实需要想想力啊,首先Canvas是一张画布,想要在画布上画一张图,就需要有笔Paint,有了笔我们这才能画,所以想要在Canvas上面画图,就需要有Paint,并且是一个带有样式的Paint
首先呢,我们需要有一个继承View的类,然后我们需要实现三个构造方法分别是:
public MyView(Context context) {
super(context, null);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initData();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initData();
}
- 第一个构造函数是在代码中实例化View的时候需要用的
- 第二个构造函数是在Xml文件文件中创建代码的时候用的所以比第一个多了一个自定义属性参数
- 第三个构造方法多了一个样式参数,是在Xml里面多一个自定义样式的时候调用的
所以在创建自定义View的时候需要同时实线这三个构造函数,关于怎样写自定义View,小编在这里就不多讲了,毕竟改文章主要是代大家熟悉Canvas的,小编会另写一篇文章教大家怎样去写自定义View,接下来我们先看一段代码
private void initData() {
mPint = new Paint();
mPint.setAntiAlias(true);
}
这是对Paint画笔的一个实例化,setAntiAlias方法主要是用来消除锯齿,是画出来的图像更加自然,圆滑,这里我们还要实现一个onSizeChanged方法,用来获取测量后的布局的宽和高
@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mRidus = Math.min(w, h) / 2;
}
这里我们定义一个圆的半径,因为我们要花表盘上的数字,由于表盘是个圆形,所以要定义一个圆形的半径,这里的半径我们选择为宽的一半,min函数用于求出宽和高中较小的那一个,设置好这些东西后,我们就开始画了,我直接上代码
/**
* 画文字
* @param canvas
*/
private void paintText(Canvas canvas) {
//将画布中心移动到屏幕中心
canvas.translate(getWidth() / 2, getHeight() / 2);
//设置画笔的颜色为红色
mPint.setColor(Color.RED);
//设置画笔的字体大小为30
mPint.setTextSize(30);
//由于表盘一圈是360度,总共有60个刻度,每个刻度是6度,所以我们这里循环60次
for (int i = 0; i < 60 ; i++) {
//当i除以5余数为0的时候,我们确定它为整点
if ( i % 5 == 0) {
//获取要显示的数字,转换成字符型
String text = (i / 5 == 0 ? 12 : i / 5) + "";
//这里实例化一个Rect主要是用来获取,需要画出来的数字的宽和高
Rect mRect = new Rect();
mPint.getTextBounds(text, 0, text.length(), mRect);
//我们获取文字的高为,基于坐标的底部距离减去顶部距离
int textHeight = mRect.bottom - mRect.top;
//保存画布
canvas.save();
//这个时候我们使用Canvas的Save方法保存了刚才的状态,这个时候我们不移动X轴,只移动Y轴,将坐标向上移动-mRidus + textHeight距离,因为对于手机来说,向上为Y的负轴,所以为-mRidus + textHeight,下面我一会用图来说明
canvas.translate(0, -mRidus + textHeight);
//由于我们没旋转一次,会使用Canvas的rotate方法顺时针旋转6度,所以文字也会跟着旋转,但是我们要让文字不旋转的话,就需要逆时针旋转相应的度数
canvas.rotate(-6 * i);
//最后使用Canvas的drawText方法画出来就可以了,由于drawText方法画汉字是从左向右的,所以x坐标为-(mRect.right - mRect.left) / 2,y坐标为mRect.bottom
canvas.drawText(text, -(mRect.right - mRect.left) / 2, mRect.bottom, mPint);
//恢复到保存最初的状态
canvas.restore();
}
//旋转6度
canvas.rotate(6);
}
//恢复到保存最初的状态
canvas.restore();
}
上面的注释,比较多,但是说的应该很清楚了,不过我还是给大家详细讲一下坐标轴的移动,首先看第一句:
canvas.translate(getWidth() / 2, getHeight() / 2);
这下应该很明白了,我们再看下一句
canvas.translate(0, -mRidus + textHeight);
最后就是将旋转的图层恢复到原来的样子,效果图就出来了,最后运行一下,怎么样还不错吧