已知通过onMeasure()
测绘view大小,通过onLayout()
知道view位置,然后就是在draw阶段实现具体绘制了
public void draw(Canvas canvas) {
if (mClipBounds != null) {
canvas.clipRect(mClipBounds);
}
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;
/* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas' layers to prepare for fading * 3. Draw view's content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) */
// Step 1, draw the background, if needed
int saveCount;
if (!dirtyOpaque) {
final Drawable background = mBackground;
if (background != null) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
if (mBackgroundSizeChanged) {
background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
mBackgroundSizeChanged = false;
}
if ((scrollX | scrollY) == 0) {
background.draw(canvas);
} else {
canvas.translate(scrollX, scrollY);
background.draw(canvas);
canvas.translate(-scrollX, -scrollY);
}
}
}
// skip step 2 & 5 if possible (common case)
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 6, draw decorations (scrollbars)
onDrawScrollBars(canvas);
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// we're done...
return;
}
/* * Here we do the full fledged routine... * (this is an uncommon case where speed matters less, * this is why we repeat some of the tests that have been * done above) */
// Step 2, save the canvas' layers
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);
//省略...
// Step 3, draw the content
if (!dirtyOpaque) onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
// Step 5, draw the fade effect and restore layers
final Paint p = scrollabilityCache.paint;
final Matrix matrix = scrollabilityCache.matrix;
final Shader fade = scrollabilityCache.shader;
//省略...
// Step 6, draw decorations (scrollbars)
onDrawScrollBars(canvas);
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
}
源码注释已经给出了绘制的指引:
1. Draw the background
2. If necessary, save the canvas’ layers to prepare for fading
3. Draw view’s content
4. Draw children
5. If necessary, draw the fading edges and restore layers
6. Draw decorations (scrollbars for instance)
翻译过来就是:
1.绘制背景 backgrond.draw
(canvas)
2.如果有必要画布保存canvas.save()
3.绘制自己onDraw()
4.绘制childrendispatchDraw()
5.如果有必要复原画布canvas.restore()
6.绘制装饰onDrawScollBars()
这里我们只关注onDraw()
绘制自己
/** * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to * draw into. The initial target density is {@link Bitmap#DENSITY_NONE}; * this will typically be replaced when a target bitmap is set for the * canvas. */
public Canvas() {
if (!isHardwareAccelerated()) {
// 0 means no native bitmap
mNativeCanvas = initRaster(0);
mFinalizer = new CanvasFinalizer(mNativeCanvas);
} else {
mFinalizer = null;
}
}
/** * Construct a canvas with the specified bitmap to draw into. The bitmap * must be mutable. * * <p>The initial target density of the canvas is the same as the given * bitmap's density. * * @param bitmap Specifies a mutable bitmap for the canvas to draw into. */
public Canvas(Bitmap bitmap) {
if (!bitmap.isMutable()) {
throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
}
throwIfCannotDraw(bitmap);
mNativeCanvas = initRaster(bitmap.ni());
mFinalizer = new CanvasFinalizer(mNativeCanvas);
mBitmap = bitmap;
mDensity = bitmap.mDensity;
}
按照注释的说法并不推荐使用无参构造函数Canvas()
而是建议我们使用Canvas(Bitmap bitmap)
同时Bitmap是可以修改的,否则将会抛出异常throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
系统也是这样做的:
onDraw( )的输入参数是一个canvas,它与我们自己创建的canvas不同。这个系统传递给我们的canvas来自于ViewRootImpl的Surface,在绘图时系统将会SkBitmap设置到SkCanvas中并返回与之对应Canvas。所以,在onDraw()中也是有一个Bitmap的,这个Bitmap是由系统创建。
void setARGB(int a, int r, int g, int b) 设置Paint对象颜色,参数一为alpha透明通道
void setAlpha(int a) 设置alpha不透明度,范围为0~255
void setAntiAlias(boolean aa) //是否抗锯齿,默认值是false
void setColor(int color) //设置颜色,这里Android内部定义的有Color类包含了一些常见颜色定义
void setFakeBoldText(boolean fakeBoldText) //设置伪粗体文本
void setLinearText(boolean linearText) //设置线性文本
PathEffect setPathEffect(PathEffect effect) //设置路径效果
Rasterizer setRasterizer(Rasterizer rasterizer) //设置光栅化
Shader setShader(Shader shader) //设置阴影 ,我们在后面会详细说一下Shader对象的
void setTextAlign(Paint.Align align) //设置文本对齐
void setTextScaleX(float scaleX) //设置文本缩放倍数,1.0f为原始
void setTextSize(float textSize) //设置字体大小
Typeface setTypeface(Typeface typeface) //设置字体,Typeface包含了字体的类型,粗细,还有倾斜、颜色等
canvas.translate 坐标系平移
canvas.rotate 坐标系旋转
canvas.clipRect 截取
canvas.save和canvas.restore 存储 复原
常常在图片截取的时候会用到,例如:图片转换成圆角矩形图片,转换成圆形图片,聚光灯效果…等等
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
不相交的部分
13.PorterDuff.Mode.DARKEN
显示两图层全部区域交集部分变暗
14.PorterDuff.Mode.LIGHTEN
显示两图层全部区域交集部分变亮
15.PorterDuff.Mode.MULTIPLY
显示两图层相交部分,交集变暗
16.PorterDuff.Mode.SCREEN
显示两图层全部区域且相交部分变成透明
BitmapShader———图像渲染
LinearGradient——–线性渲染
RadialGradient——–环形渲染
SweepGradient——–扫描渲染
ComposeShader——组合渲染
平移、缩放、颜色变化