涉及知识
绘制过程涉及到主要方法
类别
API
描述
布局
onMeasure
测量View与Child View的大小
onLayout
确定Child View的位置
onSizeChanged
确定View的大小
绘制
onDraw
实际绘制View的内容
事件处理
onTouchEvent
处理屏幕触摸事件
重绘
invalidate
调用onDraw方法,重绘View中变化的部分
Canvas涉及到主要方法
类别
API
描述
绘制图形
drawPoint、drawPoints、drawLine、drawLines、drawRect、drawRoundRect、drawOval、drawCircle、drawArc
依次为绘制点、直线、矩形、圆角矩形、椭圆、圆、散形
绘制文本
drawText、drawPosText、drawTextOnPath
依次为绘制文字、指定每个字符位置绘制文字、根据路径绘制文字
画布变换
translate、scale、rotate、skew
依次为平移、缩放、旋转、倾斜(错切)
画布裁剪
clipPath、clipRect、clipRegion
依次为按路径、按矩形、按区域或对画布进行裁剪
Paint涉及到主要方法
类别
API
描述
颜色
setColor、setARGB、setAlpha
依次为设置画笔颜色、透明度
类型
setStyle
填充(FILL),描边(STROKE),填充加描边(FLIL_STROKE)
抗锯齿
setAntiAlias
画笔是否抗锯齿
字体大小
setTextSize
设置字体到大小
字体测量
getFontMetrics()、getFontMetricsInt()
返回字体测量,返回依次为float、int
文字宽度
measureText
返回文字到宽度
文字对齐方式
setTextAlign
左对齐(LEFT)、居中对齐(CENTER)、右对齐(RIGHT)
宽度
setStrokeWidth
设置画笔宽度
笔锋
setStrokeCap
默认(BUTT),半圆形(ROUND),方形(SQUARE)
(注:因API较多,只列出常用到方法,想了解更多,请查看官方文档)
一、坐标系
1、屏幕坐标系
屏幕坐标系以手机屏幕到左上角为坐标原点,过原点的水平直线为X轴,向右为正方向;过原点的垂线为Y轴,向下为正方向;
屏幕坐标系.png
2、View坐标系
View坐标系以父视图到左上角为坐标原点,过原点的水平直线为X轴,向右为正方向;过原点的垂线为Y轴,向下为正方向
View坐标系.png
View内部拥有四个函数,用于获取View到位置
getTop(); //View的顶边到其Parent View的顶边的距离,即View的顶边与View坐标系的X轴之间的距离
getLeft(); //View的左边到其Parent View的左边的距离,即View的左边与View坐标系的Y轴之间的距离
getBottom(); //View的底边到其Parent View的顶边的距离,即View的底边与View坐标系的X轴之间的距离
getRight(); //View的右边到其Parent View的左边的距离,即View的右边与View坐标系的Y轴之间的距离
如图所示
QQ图片20170221145844.png
二、绘制过程
1、自定义属性
2、onMeasure
3、onLayout
用于确定View以及其子View的布局位置,在ViewGroup中,当位置被确定后,它在onLayout中会遍历所有到child并调用其layout,然后layout内部会再调用child到onLayout确定child view到布局位置
layout放法如下
public void layout(int l, int t, int r, int b) {
····
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;
····
for (int i = 0; i < numListeners; ++i) {
listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
}
}
}
·····
}
mLeft,mTop,mBottom,mRight四个参数分别通过getLeft(),getTop(),getBottom(),getRight(),四个函数获得,这一组old值会在位置改变时,调用onLayoutChanges时使用到
4、onSizeChanged
如其名,在View大小改变是调用此函数,用于确定View的大小。至于View大小为什么会改变,因为View的大小不仅由本身确定,同事还受父View到影响
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
这里到w、h就是确定后到高宽值,如果查看View中的onLayoutChange也会看到类似的情况,拥有l, t, r, b, oldL, oldT, oldR, oldB,新旧两组参数
5、onDraw
onDraw是View的绘制部分,给了我们一张空白的画布,使用Canvas进行绘制。也是后面几篇文章所要分享的内容。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
6、onTouchEvent
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
当返回true时,说明该View消耗了触摸事件,后续到触摸事件由它来进行处理。返回false时,说明该View对触摸事件不感兴趣,事件继续传递下去。触屏事件类型被封装在MotionEvent中,MotionEvent提供了很多类型事件,主要关系以下几种类型:
事件类型
描述
ACTION_DOWN
手指按下
ACTION_MOVE
手指移动
ACTION_UP
手指抬起
在MotionEvent中有两组可以获得触摸位置到函数
event.getX(); //触摸点相对于View坐标系的X坐标
event.getY(); //触摸点相对于View坐标系的Y坐标
event.getRawX(); //触摸点相对于屏幕坐标系的X坐标
event.getRawY(); //触摸点相对于屏幕坐标系的Y坐标
如图所示:
触摸位置.png
onWindowFocusChanged运行于onMeasure与onLayout之后,可以获取到正确的width、height、top、left等属性值。