Android 自定义 View 系列文章至今已经分析了自定义流程的 measure,layout 以及对 TouchEvent 的处理。那么接下来当然应该讲到对draw原理分析了,draw这一步骤是整个自定义过程中极为重要的一步,而今天这一篇文章就是对 draw 原理进行分析。经过 measure 测量和 layou t定位后,自定义 View 便进入了 draw 绘制阶段。
android.view.View.draw()
既然是对 draw 原理分析,那么自然首先看一下 View 的 draw() 方法源码了
在看源码之前我们先看 Google 官方文档对 android.view.View.draw() 方法的描述,这有助于我们对源码的理解:
Manually render this view (and all of its children) to the given Canvas. The view must have already done a full layout before this function is called. When implementing a view, implement onDraw(android.graphics.Canvas) instead of overriding this method. If you do need to override this method, call the superclass version.
上面的话大约有以下几点需要注意:
在给定的画布(canvas)上手动渲染这个视图(以及它所有的子视图(子 view))
在调用此函数之前,视图必须已经完成了完整的布局
当实现一个视图时,实现o nDraw(android.graphics.Canvas)而不是覆盖(重写)这个方法
如果你确实需要重写这个方法,调用超类的版本
我们可以看到绘制(draw)的操作是在canvas(画布)上进行的,所以这里我们再来了解一下Canvas类吧!
Google官方文档对 Canvas类 的描述如下:
The Canvas class holds the “draw” calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint (to describe the colors and styles for the drawing).
以上信息主要有以下几点:
Canvas 类保存对 draw() 方法的调用
如果要进行绘制(draw),需要四个基本组成部分
储存绘制的内容,用于保存像素的位图(Bitmap )、一个 Canvas 来承载绘制调用(写入位图,调用各种方法,如 canvas.drawLine()、canvas。drawPaint())、绘图图元(根据自己需求绘制,例如圆(Rect),路径(Path),文本,Bitmap)、画笔(Paint,描述绘图的颜色和风格)
我们可以看到 Canvas 类在 draw 过程中起着重要的作用,接下来我们直接上源码
public void draw(Canvas canvas) {
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
int saveCount;
if (!dirtyOpaque) {
drawBackground(canvas);
}
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
if (!dirtyOpaque) onDraw(canvas);
dispatchDraw(canvas);
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
onDrawForeground(canvas);
return;
}
boolean drawTop = false;
boolean drawBottom = false;
boolean drawLeft = false;
boolean drawRight = false;
float topFadeStrength = 0.0f;
float bottomFadeStrength = 0.0f;
float leftFadeStrength = 0.0f;
float rightFadeStrength = 0.0f;
int paddingLeft = mPaddingLeft;
final boolean offsetRequired = isPaddingOffsetRequired();
if (offsetRequired) {
paddingLeft += getLeftPaddingOffset();
}
int left = mScrollX + paddingLeft;
int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
int top = mScrollY + getFadeTop(offsetRequired);
int bottom = top + getFadeHeight(offsetRequired);
if (offsetRequired) {
right += getRightPaddingOffset();
bottom += getBottomPaddingOffset();
}
final ScrollabilityCache scrollabilityCache = mScrollCache;
final float fadeHeight = scrollabilityCache.fadingEdgeLength;
int length = (int) fadeHeight;
if (verticalEdges && (top + length > bottom - length)) {
length = (bottom - top) / 2;
}
if (horizontalEdges && (left + length > right - length)) {
length = (right - left) / 2;
}
if (verticalEdges) {
topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
drawTop = topFadeStrength * fadeHeight > 1.0f;
bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));
drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
}
if (horizontalEdges) {
leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));
drawLeft = leftFadeStrength * fadeHeight > 1.0f;
rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));
drawRight = rightFadeStrength * fadeHeight > 1.0f;
}
saveCount = canvas.getSaveCount();
int solidColor = getSolidColor();
if (solidColor == 0) {
final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
if (drawTop) {
canvas.saveLayer(left, top, right, top + length, null, flags);
}
if (drawBottom) {
canvas.saveLayer(left, bottom - length, right, bottom, null, flags);
}
if (drawLeft) {
canvas.saveLayer(left, t