这里有新鲜出炉的精品教程,程序狗速度看过来!
Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由Google公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。
这篇文章主要介绍了Android View刷新机制,结合实例形式较为详细的分析了Android的View刷新机制功能、原理与具体使用技巧,需要的朋友可以参考下
本文实例讲述了Android View刷新机制。分享给大家供大家参考,具体如下:
一、总体说明
在Android的布局体系中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成。
二、代码分析
1).ViewGroup的addView方法,理解参数的意义和传递
invalidate调用父类View的方法
addViewInner方法主要做的事情是
view的dispatchAttachedToWindow(AttachInfo info, int visibility)方法
1).View的invalidate方法,这是一个从下第向上回溯的过程,每一层的父View都将自己的显示区域与传入的刷新
Rect做交集。
- void invalidate(boolean invalidateCache) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE);
- }
- if (skipInvalidate()) {
- return;
- }
- if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) || (invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) || (mPrivateFlags & INVALIDATED) != INVALIDATED || isOpaque() != mLastIsOpaque) {
- mLastIsOpaque = isOpaque();
- mPrivateFlags &= ~DRAWN;
- mPrivateFlags |= DIRTY;
- if (invalidateCache) {
- mPrivateFlags |= INVALIDATED;
- mPrivateFlags &= ~DRAWING_CACHE_VALID;
- }
- final AttachInfo ai = mAttachInfo;
- final ViewParent p = mParent;
- //noinspection PointlessBooleanExpression,ConstantConditions
- if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
- if (p != null && ai != null && ai.mHardwareAccelerated) {
- // fast-track for GL-enabled applications; just invalidate the whole hierarchy
- // with a null dirty rect, which tells the ViewAncestor to redraw everything
- p.invalidateChild(this, null);
- return;
- }
- }
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- // Don't call invalidate -- we don't want to internally scroll
- // our own bounds
- p.invalidateChild(this, r); //调用子类的方法完成
- }
- }
- }
2)ViewGrop的invalidateChild方法
- public final void invalidateChild(View child, final Rect dirty) {
- ViewParent parent = this;
- final AttachInfo attachInfo = mAttachInfo;
- if (attachInfo != null) {
- final int[] location = attachInfo.mInvalidateChildLocation;
- // 需要刷新的子View的位置
- location[CHILD_LEFT_INDEX] = child.mLeft;
- location[CHILD_TOP_INDEX] = child.mTop;
- // If the child is drawing an animation, we want to copy this flag onto
- // ourselves and the parent to make sure the invalidate request goes through
- final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
- // Check whether the child that requests the invalidate is fully opaque
- final boolean isOpaque = child.isOpaque() && !drawAnimation && child.getAnimation() != null;
- // Mark the child as dirty, using the appropriate flag
- // Make sure we do not set both flags at the same time
- final int opaqueFlag = isOpaque ? DIRTY_OPAQUE: DIRTY;
- do {
- View view = null;
- if (parent instanceof View) {
- view = (View) parent;
- }
- if (drawAnimation) {
- if (view != null) {
- view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRoot) { ((ViewRoot) parent).mIsAnimating = true;
- }
- }
- // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
- // flag coming from the child that initiated the invalidate
- if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
- view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
- }
- parent = parent.invalidateChildInParent(location, dirty);
- } while ( parent != null );
- }
- }
- public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
- if ((mPrivateFlags & DRAWN) == DRAWN) {
- if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) != FLAG_OPTIMIZE_INVALIDATE) {
- // 根据父View的位置,偏移刷新区域
- dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX, location[CHILD_TOP_INDEX] - mScrollY);
- final int left = mLeft;
- final int top = mTop;
- //计算实际可刷新区域
- if (dirty.intersect(0, 0, mRight - left, mBottom - top) || (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
- mPrivateFlags &= ~DRAWING_CACHE_VALID;
- location[CHILD_LEFT_INDEX] = left;
- location[CHILD_TOP_INDEX] = top;
- return mParent;
- }
- } else {
- mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
- location[CHILD_LEFT_INDEX] = mLeft;
- location[CHILD_TOP_INDEX] = mTop;
- dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX], mBottom - location[CHILD_TOP_INDEX]);
- return mParent;
- }
- }
- return null;
- }
这个向上回溯的过程直到ViewRoot那里结束,由ViewRoot对这个最终的刷新区域做刷新
ViewRoot.java
- public void invalidateChild(View child, Rect dirty) {
- }
由ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View树,值得注意的是每次发起绘图时,并不会重新绘制每个View树的视图,而只会重新绘制那些“需要重绘”的视图,View类内部变量包含了一个标志位DRAWN,当该视图需要重绘时,就会为该View添加该标志位。
调用流程 :
mView.draw()开始绘制,draw()方法实现的功能如下:
1 、绘制该View的背景
2 、为显示渐变框做一些准备操作(见5,大多数情况下,不需要改渐变框)
3、调用onDraw()方法绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)
4、调用dispatchDraw ()方法绘制子视图(如果该View类型不为ViewGroup,即不包含子视图,不需要重载该
方法)值得说明的是,ViewGroup类已经为我们重写了dispatchDraw ()的功能实现,应用程序一般不需要重写该
方法,但可以重载父类函数实现具体的功能。
4.1 dispatchDraw()方法内部会遍历每个子视图,调用drawChild()去重新回调每个子视图的draw()方法(注意,这个 地方“需要重绘”的视图才会调用draw()方法)。值得说明的是,ViewGroup类已经为我们重写了dispatch
Draw()的功能实现,应用程序一般不需要重写该方法,但可以重载父类函数实现具体的功能。
希望本文所述对大家Android程序设计有所帮助。
来源: http://www.phperz.com/article/17/0914/348928.html