前言
Android里面的绘制都是按顺序的,先绘制的会被后绘制的盖住。我们要学会实现自己所需要的遮盖关系
super.onDraw()
// 直接继承View的话,是无所谓的,因为onDraw()方法是空实现
// 继承某一个已知的控件,就有分别了
// super.onDraw()下面:绘制内容覆盖原有内容,比如打印图像尺寸信息
// super.onDraw()上面:绘制内容被原有内容覆盖,比如给TextView加一个底色
dispatchDraw()
// 子View的绘制会遮盖ViewGroup的绘制,所以在onDraw()无法实现遮盖子View
// dispatchView()只对ViewGroup有意义
// super.dispatchDraw()下面:可以盖住子View
// super.dispatchDraw()上面:和在onDraw()下面写的效果是一样的
绘制过程简述
// 背景:无法重写
drawBackground()
// 主体:我们常重写的
onDraw()
// 绘制子View的方法
dispatchDraw()
// 滑动边缘渐变和滑动条、前景
onDrawForeground()
注意:前景的支持是在android6.0之后,之前只支持FrameLayout
onDrawForeground()
// 此方法是在API23的时候才引入的,此方法会依次绘制滑动边缘渐变、滑动条和前景
// super.onDrawForeground()下面:盖住滑动边缘渐变、滑动条、前景
// super.onDrawForeground()上面:盖住子View,但被滑动边缘渐变、滑动条、前景盖住
// 注意:想在滑动边缘渐变、滑动条和前景之间插入绘制代码? NoNoNo,不可以的
draw()总调度方法
// 大致的一个结构
public void draw(Canvas canvas) {
...
drawBackground(Canvas); // 绘制背景(不能重写)
onDraw(Canvas); // 绘制主体
dispatchDraw(Canvas); // 绘制子 View
onDrawForeground(Canvas); // 绘制滑动相关和前景
...
}
// super.draw()下面:会盖住所有的绘制内容
// super.draw()上面:被所有其他内容盖住,比如,在背景下加一个下划线
注意点:
// 出于效率的考虑,ViewGroup默认会绕过draw()方法,换而直接执行dispatchDraw()方法,以此来简化绘制流程。在除dispatchDraw()以外的方法绘制内容,可能需要调用View.setWillNotDraw(false)来切换的完整的绘制流程,但有些ViewGroup已经调用过此方法了,比如ScrollView
// 如果绘制代码既可以写在onDraw()里, 也可以写在其他绘制方法里, 那么优先写在onDraw(),因为Android有相关的优化,可以在不需要重绘的时候自动跳过onDraw()的重复执行,以提升开发效率
总结
其实只要牢记draw()的调度就OK了,剩下在前在后,只不过代码执行顺序的问题而已了,很好记忆
贴个HenCoder的链接:自定义View-绘制顺
分割线---------------------------------------------------------------------------------
实践
// 1 图片上打印尺寸信息, onDraw()后插
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// todo 打印尺寸信息
}
// 2 给TextView绘制黄色背景, onDraw()前插
@Override
protected void onDraw(Canvas canvas) {
// todo 绘制黄色背景
super.onDraw(canvas);
}
// 3 画粉色斑点
// 记得调用setWillNotDraw(false)以启动完整的绘制流程;
// 4 让绘制的粉色斑点盖住子View
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
// todo 绘制粉色斑点
}
// 5 绘制的标签盖住黑色前景, onDrawForeground()后插
@Override
public void onDrawForeground(Canvas canvas) {
super.onDrawForeground(canvas);
// todo 绘制标签
}
// 6 绘制的标签被前景盖住, onDrawForeground()前插
@Override
public void onDrawForeground(Canvas canvas) {
// todo 绘制标签
super.onDrawForeground(canvas);
}
// 7 盖在其他所有, draw()方法后插
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
// todo 绘制标签
}
// 8 编辑框的背景就是下划线的情况下, 在下划线下再加一层背景, draw()方法前插
@Override
public void draw(Canvas canvas) {
// todo 绘制背景
super.draw(canvas);
}