1、Android自定义View一(基础和原理)
http://blog.csdn.net/androidxiaogang/article/details/51849136
2、onMeasure(),onLayout()方法的和内部实现
http://blog.csdn.net/androidxiaogang/article/details/51880753
在自定义View的时候可以重写draw和onDraw()方法
从方法的上描述看:调用draw()的时候,必须手动的给view指定在Canvas,当实现自定义view的时候用onDraw(android.graphics.Canvas)这个方法代替。
虽然已经不推荐使用了,但还是应该分析一下它内部的流程
1. Draw the background(绘制背景)
2. If necessary, save the canvas’ layers to prepare for fading(如果需要,为保存这层为边缘的滑动效果作准备)
3. Draw view’s content(绘制内容)
4. Draw children(绘制子View)
5. If necessary, draw the fading edges and restore layers(如果需要,绘制边缘效果并且保存图层)
6. Draw decorations (scrollbars for instance)(绘制边框,比如scrollbars,其实每一个view,比如TextView也是有滚动条的,只是设置的显示或者不显示,或者gone)
接下来一步一步分析:
// Step 1, draw the background, if needed
int saveCount;
if (!dirtyOpaque) {
drawBackground(canvas);
}
第一部,比较简单,就是绘制view的背景
// skip step 2 & 5 if possible (common case)
正常情况下,我们一般不用管这两步,这两步的主要作用是当我们滑动到view边缘时产生的效果(比如滑动到边一些阴影)一般开发中也用不到这种效果。因此跳过2和5
// Step 3, draw the content
if (!dirtyOpaque) onDraw(canvas);
看到这个方法就明白了吧,原来draw()内部是调用onDraw()实现的
// Step 4, draw the children
dispatchDraw(canvas);
/**
* Draw any foreground content for this view.
*
* Foreground content may consist of scroll bars, a {@link #setForeground foreground}
* drawable or other view-specific decorations. The foreground is drawn on top of the
* primary view content.
*
* @param canvas canvas to draw into
*/
public void onDrawForeground(Canvas canvas) {
onDrawScrollIndicators(canvas);
onDrawScrollBars(canvas);
final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
if (foreground != null) {
if (mForegroundInfo.mBoundsChanged) {
mForegroundInfo.mBoundsChanged = false;
final Rect selfBounds = mForegroundInfo.mSelfBounds;
final Rect overlayBounds = mForegroundInfo.mOverlayBounds;
if (mForegroundInfo.mInsidePadding) {
selfBounds.set(0, 0, getWidth(), getHeight());
} else {
selfBounds.set(getPaddingLeft(), getPaddingTop(),
getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
}
final int ld = getLayoutDirection();
Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld);
foreground.setBounds(overlayBounds);
}
foreground.draw(canvas);
}
}
从上面draw()方法可以看出,即使在draw()内部也是调用了onDraw()方法,draw()方法的使用其实帮我们绘制一些比较特别的东西,比如view边缘滑动时的阴湿,和滚动条之类的。但在实际开发这,这些一般是用不到了,这也是android API是
建议我们使用onDraw()方法的原因。
进入onDraw()方法中:
/**
* Implement this to do your drawing.
*
* @param canvas the canvas on which the background will be drawn
*/
protected void onDraw(Canvas canvas) {
}
这个方法是一个空的实现。当看到源码中有空实现的时候,这就是要求我们自已去实现。
在上面draw()的第四步中,看到调用dispatchDraw是绘制子View的,在View与ViewGroup中的代码不同:
在View中
在View中是一个空的实现,因为View中可以没有自已的子View,但在ViewGroup中,它一定有自已的子类。
从上面的分析可以看出自定义View最终调用的是用onDraw()进行绘制了,而且是一个空的实现,那么所有工作就转移到我们传入的参数Canvas中,了解这个类的使用,帮助我们绘制出各种不同的效果。
看API介绍
Canvas被draw调用,当draw的时候需要4个基本的元素
1、a Bitmap to hold the pixels (一个图片,最终呈现我们画的东西)
2、a Canvas to host the draw calls (writing into the bitmap)(把canvas绘制到图片中)
3、a drawing primitive (e.g. Rect, Path, text, Bitmap), (绘制的具体内容,可以文本,图片,形状之类)
4、a paint (to describe the colors and styles for the drawing).(绘制需要的工具,大小,颜色)