热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

androidView绘制源码分析(下)

Layout的过程viewGroup会遍历所有子元素并调用其layout方法,layout方法来确定子元素的位置。viewgroup如下:prote

Layout的过程

viewGroup会遍历所有子元素并调用 其layout方法,layout方法来确定子元素的位置。viewgroup如下:

protected abstract void onLayout(boolean changed,int l , int t, int r, int b) ;

需要子类自己实现。看下view的layout:

public void layout(int l, int t , int r, int b) {if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT ) != 0) {onMeasure(mOldWidthMeasureSpec , mOldHeightMeasureSpec) ;mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;}int oldL = mLeft;int oldT = mTop;int oldB = mBottom;int oldR = mRight;boolean changed = isLayoutModeOptical( mParent) ?setOpticalFrame(l, t , r, b) : setFrame(l, t , r, b);if (changed || ( mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED ) {onLayout(changed, l, t , r, b);mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;ListenerInfo li = mListenerInfo;if (li != null && li.mOnLayoutChangeListeners != null) {ArrayList listenersCopy =(ArrayList)li. mOnLayoutChangeListeners .clone();int numListeners = listenersCopy.size() ;for ( int i = 0 ; i }

在setFrame中确定了view的四个顶点坐标。mleft等。onLayout view也没有具体实现,要看具体的。以LinearLayout为例:

protected void onLayout(boolean changed, int l , int t, int r, int b) {if (mOrientation == VERTICAL) {layoutVertical(l, t, r , b);} else {layoutHorizontal(l, t, r , b);}
}

以layoutVertical为例:

void layoutVertical(int left, int top , int right, int bottom) {final int paddingLeft = mPaddingLeft ;int childTop ;int childLeft ;// Where right end of child should gofinal int width = right - left;int childRight = width - mPaddingRight ;// Space available for childint childSpace = width - paddingLeft - mPaddingRight ;final int count = getVirtualChildCount() ;final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;final int minorGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;switch (majorGravity) {case Gravity.BOTTOM:// mTotalLength contains the padding alreadychildTop = mPaddingTop + bottom - top - mTotalLength;break;// mTotalLength contains the padding alreadycase Gravity.CENTER_VERTICAL:childTop = mPaddingTop + (bottom - top - mTotalLength) / 2;break;case Gravity. TOP:default :childTop = mPaddingTop;break;}for (int i = 0; i }

主要看以下代码:

final int childWidth = child.getMeasuredWidth() ;
final int childHeight = child.getMeasuredHeight() ;
setChildFrame(child , childLeft, childTop + getLocationOffset(child) ,childWidth , childHeight);
childTop += childHeight + lp. bottomMargin + getNextLocationOffset(child);

top会逐渐增大,所以会往下排。setChildFrame仅仅是调用子元素的layout方法。

private void setChildFrame(View child, int left, int top , int width, int height) {       child.layout(left, top, left + width , top + height);
}

通过子元素的layout来确定自身。

draw过程

它有以下几步:

  • 绘制背景,(canvas)

  • 绘制自己。(onDraw)

  • 绘制children(dispatchDraw)

  • 绘制装饰(onDrawScrollBars)

看下view的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;/** 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 neededint saveCount;if (!dirtyOpaque) {drawBackground(canvas);}// 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 contentif (!dirtyOpaque) onDraw(canvas) ;// Step 4, draw the childrendispatchDraw(canvas) ;// Step 6, draw decorations (scrollbars)onDrawScrollBars(canvas) ;if ( mOverlay != null && !mOverlay.isEmpty()) {mOverlay .getOverlayView().dispatchDraw(canvas) ;}// we're done...return;}

viewgroup中的dispatchDraw用于遍历子view并调用子view的draw方法。这样就一层层的传下去。到此源码分析就结束了。在绘制view的时候经常会在activity中获得view的宽高,因为activity的生命周期和view不同步,在oncreate中无法获取到view的宽高,接下来讲讲activity中如何获取view。

三、view宽高确定


  • onWindowFocusChanged:view己经初始化完毕,宽高己经准备好。当Activity得到焦点和失去焦点均会被调用,所以它会调用多次。

  • 通过view.post,将一个runnable投弟到消息队列尾部,等待looper调用时,view己经初始化好。

protected void onStart(){
super.onStart();
view.post(new Runnable(){
public void run(){
int width = view.getMeasuredWidth();
int height = new .getMeasuredHeight();
}
})
}


  • ViewTreeObserver: 

    使用ViewTreeObserver众多回调接口来完成,如OnGlobalLayoutListener,当view树状态发生改变时或内部view可见性发生改变时会回调。

ViewObserver obserber = view.getViewObserver ();
obserber.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
public void onGlobalLayout(){
obserber.removeOnGlobalLayoutListener(this);
int width = view.getMeasuredWidth();
int height = new .getMeasuredHeight();
}
})


  • 通过view进行measure来得到view的宽高。

int width = MeasureSpec.makeMeasureSpec(100,Measure.EXACTLY);//确定值
int height= MeasureSpec.makeMeasureSpec(100,Measure.EXACTLY);//确定值
view.measure(width,height);
对于wrap_content:
int width &#61; MeasureSpec.makeMeasureSpec((1<<30)-1,Measure.AT_MOST);//wrap_content
int height&#61; MeasureSpec.makeMeasureSpec((1<<30)-1,Measure.AT_MOST);//wrap_content
view.measure(width,height);


四、自定义view中注意事项

自定义View需要注意的事项&#xff1a;

  • 如果是继承view或者viewGroup&#xff0c;让view支持wrap_content。

  • 如果有必要&#xff0c;让view支持padding。

  • View中如果有动画或者线程&#xff0c;要在onDetachedFromWindow中及时停止。当view的Activity退出或者当前view被remove时&#xff0c;调用它。


推荐阅读
  • 本文介绍了GregorianCalendar类的基本信息,包括它是Calendar的子类,提供了世界上大多数国家使用的标准日历系统。默认情况下,它对应格里高利日历创立时的日期,但可以通过调用setGregorianChange()方法来更改起始日期。同时,文中还提到了GregorianCalendar类为每个日历字段使用的默认值。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了Python函数的定义与调用的方法,以及函数的作用,包括增强代码的可读性和重用性。文章详细解释了函数的定义与调用的语法和规则,以及函数的参数和返回值的用法。同时,还介绍了函数返回值的多种情况和多个值的返回方式。通过学习本文,读者可以更好地理解和使用Python函数,提高代码的可读性和重用性。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
狮子小刚刚
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有