`
xixinfei
  • 浏览: 410899 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

android-View工作原理(四)view的layout过程

 
阅读更多
	刚过完自己的本命年,新的一年希望自己有个新的开始,祝自己在新的一年里一帆风顺,同时也祝广大的朋友们新年新气象,收获多多!

 

一、android中view的layout过程总概

 

	Layout过程其实就是父视图按照子视图的大小及布局参数将子视图放在窗口的合适的位置上。

 

	视图的布局过程是从ViewRoot对象调调用根视图的layout()方法开始,接着layout()方法调用根视图的onLayout()方法,onLayout()方法会对所包含的子视图逐一执行layout操作,如果子视图是ViewGroup子类对象,则继续调用子视图的layout(),重复这一过程。如果子视图是View子类对象,则在子视图重载的onLayout()内部只需要将自己布局到视图中,不需要对子视图进行layout操作,这样一次layout过程结束。过程如下图:

 

 

 

 

转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17784911

 

二、layout详细过程

 

View中的layout()方法源码(ViewGroup类继承了View类,layout过程先从ViewGroup子类开始):

 

  1. /** 
  2.     * Assign a size and position to a view and all of its 
  3.     * descendants 
  4.     * 
  5.     * <p>This is the second phase of the layout mechanism. 
  6.     * (The first is measuring). In this phase, each parent calls 
  7.     * layout on all of its children to position them. 
  8.     * This is typically done using the child measurements 
  9.     * that were stored in the measure pass(). 
  10.     * 
  11.     * Derived classes with children should override 
  12.     * onLayout. In that method, they should 
  13.     * call layout on each of their their children. 
  14.     * 
  15.     * @param l Left position, relative to parent 
  16.     * @param t Top position, relative to parent 
  17.     * @param r Right position, relative to parent 
  18.     * @param b Bottom position, relative to parent 
  19.     */  
  20.    public final void layout(int l, int t, int r, int b) {  
  21.        boolean changed = setFrame(l, t, r, b);  
  22.        if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {  
  23.            if (ViewDebug.TRACE_HIERARCHY) {  
  24.                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);  
  25.            }  
  26.   
  27.            onLayout(changed, l, t, r, b);  
  28.            mPrivateFlags &= ~LAYOUT_REQUIRED;  
  29.        }  
  30.        mPrivateFlags &= ~FORCE_LAYOUT;  
  31.    }  

 

 

a) 首先我们看这个方法的定义,用了关键字final,说明此方法是不可被重写的,这样也就保证了Viewlayout过程是不变的。四个参数看注释,左、上、右、下分别相距父视图的距离。

b) 调用setFrame(l,t,r,b)将位置保存起来,这些参数将保存到View内部变量 (mLeftmTopmRightmBottom)中。保存完变量前,会先对比这些参数是否和原来的相同,如果相同,则什么都不做,如果不同则进行重新赋值,并在赋值前给mPrivateFlags中添加DRAWN标识,同时调用invalidate()通知View系统原来占用的位置需要重绘。

c) 调用onLayout(),View中定义的onLayout()方法默认什么都不做,View系统提供onLayout()方法的目的是为了使系统包含的子视图的父视图能够在onLayout()方法对子视图进行位置分配,正因为如此,如果是父视图,则必须重写onLayout(),也正因为如此ViewGroup类才会把onLayout重载改成了abstract类型。

d)清除mPrivateFlags中的LAYOUT_REQUIRED标识,因为layout操作已经完成。

上面提到的setFrame方法源码如下:

  1. protected boolean setFrame(int left, int top, int right, int bottom) {  
  2.         boolean changed = false;  
  3.         if (DBG) {  
  4.             Log.d("View"this + " View.setFrame(" + left + "," + top + ","  
  5.                     + right + "," + bottom + ")");  
  6.         }  
  7.         if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {  
  8.             changed = true;  
  9.             // Remember our drawn bit  
  10.             int drawn = mPrivateFlags & DRAWN;  
  11.             // Invalidate our old position  
  12.             invalidate();  
  13.             int oldWidth = mRight - mLeft;  
  14.             int oldHeight = mBottom - mTop;  
  15.             mLeft = left;  
  16.             mTop = top;  
  17.             mRight = right;  
  18.             mBottom = bottom;  
  19.             mPrivateFlags |= HAS_BOUNDS;  
  20.             int newWidth = right - left;  
  21.             int newHeight = bottom - top;  
  22.             if (newWidth != oldWidth || newHeight != oldHeight) {  
  23.                 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);  
  24.             }  
  25.             if ((mViewFlags & VISIBILITY_MASK) == VISIBLE) {  
  26.                 // If we are visible, force the DRAWN bit to on so that  
  27.                 // this invalidate will go through (at least to our parent).  
  28.                 // This is because someone may have invalidated this view  
  29.                 // before this call to setFrame came in, therby clearing  
  30.                 // the DRAWN bit.  
  31.                 mPrivateFlags |= DRAWN;  
  32.                 invalidate();  
  33.             }  
  34.             // Reset drawn bit to original value (invalidate turns it off)  
  35.             mPrivateFlags |= drawn;  
  36.             mBackgroundSizeChanged = true;  
  37.         }  
  38.         return changed;  
  39.     }  

 

 View中的onLayout()方法如下:

 

  1. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  2.     }  

 

而ViewGroup中的onLayout()方法如下:

 

  1. @Override  
  2.     protected abstract void onLayout(boolean changed,  
  3.             int l, int t, int r, int b);  

 

 

 

转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17784911 

 

因为ViewGroup中的onLayout()方法是一个抽象方法,所以下面我们用他的子类LinearLayout中的onLayout()方法来分析。源码如下:

 

onlayout()方法:

 

  1. @Override  
  2.    protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  3.        if (mOrientation == VERTICAL) {  
  4.            layoutVertical();  
  5.        } else {  
  6.            layoutHorizontal();  
  7.        }  
  8.    }  

 

layoutVertical()方法源码:

 

  1. void layoutVertical() {  
  2.         final int paddingLeft = mPaddingLeft;  
  3.         int childTop = mPaddingTop;  
  4.         int childLeft;  
  5.         // Where right end of child should go  
  6.         final int width = mRight - mLeft;  
  7.         int childRight = width - mPaddingRight;  
  8.         // Space available for child  
  9.         int childSpace = width - paddingLeft - mPaddingRight;  
  10.         final int count = getVirtualChildCount();  
  11.         final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;  
  12.         final int minorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;  
  13.         if (majorGravity != Gravity.TOP) {  
  14.            switch (majorGravity) {  
  15.                case Gravity.BOTTOM:  
  16.                    // mTotalLength contains the padding already, we add the top  
  17.                    // padding to compensate  
  18.                    childTop = mBottom - mTop + mPaddingTop - mTotalLength;  
  19.                    break;  
  20.                case Gravity.CENTER_VERTICAL:  
  21.                    childTop += ((mBottom - mTop)  - mTotalLength) / 2;  
  22.                    break;  
  23.            }  
  24.         }  
  25.         for (int i = 0; i < count; i++) {  
  26.             final View child = getVirtualChildAt(i);  
  27.             if (child == null) {  
  28.                 childTop += measureNullChild(i);  
  29.             } else if (child.getVisibility() != GONE) {  
  30.                 final int childWidth = child.getMeasuredWidth();  
  31.                 final int childHeight = child.getMeasuredHeight();  
  32.                 final LinearLayout.LayoutParams lp =  
  33.                         (LinearLayout.LayoutParams) child.getLayoutParams();  
  34.                 int gravity = lp.gravity;  
  35.                 if (gravity < 0) {  
  36.                     gravity = minorGravity;  
  37.                 }  
  38.                 switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {  
  39.                     case Gravity.LEFT:  
  40.                         childLeft = paddingLeft + lp.leftMargin;  
  41.                         break;  
  42.                     case Gravity.CENTER_HORIZONTAL:  
  43.                         childLeft = paddingLeft + ((childSpace - childWidth) / 2)  
  44.                                 + lp.leftMargin - lp.rightMargin;  
  45.                         break;  
  46.                     case Gravity.RIGHT:  
  47.                         childLeft = childRight - childWidth - lp.rightMargin;  
  48.                         break;  
  49.                     default:  
  50.                         childLeft = paddingLeft;  
  51.                         break;  
  52.                 }  
  53.                 childTop += lp.topMargin;  
  54.                 setChildFrame(child, childLeft, childTop + getLocationOffset(child),  
  55.                         childWidth, childHeight);  
  56.                 childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);  
  57.                 i += getChildrenSkipCount(child, i);  
  58.             }  
  59.         }  
  60.     }  

 

	a) LinearLayout中的子视图有两种布局方式,一个是纵向的,一个是横向的,这里我们以纵向的分析。

 

	b) 获得子视图的宽度。

 

	c) 根据父视图中的grarity属性,来判断子视图的起始位置。

 

	d) 开始for()循环,为每个子视图分配位置。对于每个子视图首先取出子视图的LayoutParams属性,并且获得gravity的值。根据gravity的值确定水平方向的起始位置,三种值分别为:LEFT,CENTER_HORIZONTAL和RIGHT.接着调用setChildFrame(),该方法内部实际上就是调用child.layout()为子视图设置布局位置。


转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17784911

分享到:
评论

相关推荐

    Android代码-sample-of-Android-week-view

    This is a sample of android week view,Thanks the author of android week view ,The WeekHeaderView is based on android week view .This project contains two view ,the header view and day view.You can add...

    Android代码-android-split-pane-layout

    Android Split Pane Layout An Android layout which splits the available space between two child views. An optionally movable bar exists between the children which allows the user to redistribute the ...

    Android-Search-View-Layout.zip

    Android-Search-View-Layout.zip,材料设计搜索视图布局,现在在google地图、拨号器等中实现,安卓系统是谷歌在2008年设计和制造的。操作系统主要写在爪哇,C和C 的核心组件。它是在linux内核之上构建的,具有安全性...

    Android-自定义RadiusView包含常用的Layout和View方便扩展

    自定义 RadiusView,包含常用的 Layout 和 View,方便扩展

    Android代码-simple-view-behavior

    Simple View Behavior for Android CoordinatorLayout. This library provide you easy ways to config and setup the view behavior without creating subclass of Behavior Installation compile '...

    Search-View-LayoutAndroid.zip

    Search-View-LayoutAndroid,Lollipop+ Dialer和Google Maps的实现,博客附件,效果请查看博客相对应项目。

    Android代码-image-zoom-view

    2) Add the view to your layout XML. implementation 'com.github.hsmnzaydn:imagezoom:1.2.1' 3) Add the view to your layout XML. &lt;com.ozaydin.serkan.com.image_zoom_view.ImageViewZoom android:layou

    Android代码-android-drag-FlowLayout

    this is a draggable flow layout lib (android 可拖拽的流布局库) . Sample apk/示例app 特点 1, 类似可拖拽的GridView. 不过gridView 宽度/个数是固定的。 这个布局item宽度是不定的(放不下自动换行)。 2,...

    Android代码-swappy-image-view

    swappy-image-view An image change/sort view for editing profile, image slider, product...Add swappy image view to your layout xml Add image from gallery/camera Implement OnSwappyListener to your activit

    Android代码-android-swipecards-view

    Add SwipeCardView to the layout xml file where it is needed The various customisation attribures available are max_visible - maximum card to be show in stack as visible min_adapter_stack - minimum ...

    Android代码-rotate-layout

    Custom layout that can rotate it's view Usage In your layout file add &lt;!-- Specify rotate angle here --&gt; Voila! Your layout will be rotated 90 degrees. Download compile 'rongi.rotate-...

    Android代码-bottomify-navigation-view

    bottomify-navigation-view A nice looking Spotify like bottom navigation view Usage Create Menu File Create a menu file below resource folder. Right click to res then New &gt; Android Resource File, ...

    Android代码-Android-FloatWindow

    View contentView = inflater.inflate(R.layout.layout_pop, null); NewFloatMainWindow.getFloatMainWindow(MainActivity.this, NewFloatMainWindow.LOCATION_LEFT, contentView); 3.实现悬浮窗如此简单 readme-...

    Android代码-gif-movie-view

    Android View widget for displaying GIF animations. To show animated GIF in your application just add GifMovieView into your layout. You can set Movie object dynamically or as a resource ID and control...

    Android-VideoCropView:裁剪视频的ViewView

    裁剪视频的ViewView 更新 1.1.1 添加原始比例选项 例子 添加build.gradle implementation ' com.crust87:video-crop-view:1.4.0 ' 附加您的布局xml &lt; android .support.constraint.ConstraintLayout xmlns :...

    [Android-Demo]Android View的拖动

    主要讲述的是: View.layout(a,b,c,d)4个参数 和getRawX和getX的区分 详细描述:http://blog.csdn.net/u011634756/article/details/10001119 ====================关注小鱼=================== 新浪微博:...

    实验2-Android-应用的界面开发(1).doc

    import android.view.Gravity; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.Button; import android.widget.EditText; import android.widget....

    android-segmented-control-view-可自定义样式、功能比较全的分段控件.zip

    项目地址:https://github.com/klongmitre/android-segmented-control-view效果图:如何使用xml中直接创建  android:id="@ id/androidSegmentedControlView"  android:layout_width="match_parent"  android:...

    Android代码-DraggableGridView

    = DraggableGridView a drag-and-drop scrolling grid view for Android == Including in your project ...Add the view to your activity's layout XML and save it: Obtain a reference to the view to use in co

Global site tag (gtag.js) - Google Analytics