刚过完自己的本命年,新的一年希望自己有个新的开始,祝自己在新的一年里一帆风顺,同时也祝广大的朋友们新年新气象,收获多多!
一、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子类开始):
- /**
- * Assign a size and position to a view and all of its
- * descendants
- *
- * <p>This is the second phase of the layout mechanism.
- * (The first is measuring). In this phase, each parent calls
- * layout on all of its children to position them.
- * This is typically done using the child measurements
- * that were stored in the measure pass().
- *
- * Derived classes with children should override
- * onLayout. In that method, they should
- * call layout on each of their their children.
- *
- * @param l Left position, relative to parent
- * @param t Top position, relative to parent
- * @param r Right position, relative to parent
- * @param b Bottom position, relative to parent
- */
- public final void layout(int l, int t, int r, int b) {
- boolean changed = setFrame(l, t, r, b);
- if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);
- }
- onLayout(changed, l, t, r, b);
- mPrivateFlags &= ~LAYOUT_REQUIRED;
- }
- mPrivateFlags &= ~FORCE_LAYOUT;
- }
a) 首先我们看这个方法的定义,用了关键字final,说明此方法是不可被重写的,这样也就保证了View的layout过程是不变的。四个参数看注释,左、上、右、下分别相距父视图的距离。
b) 调用setFrame(l,t,r,b)将位置保存起来,这些参数将保存到View内部变量 (mLeft、mTop、mRight、mBottom)中。保存完变量前,会先对比这些参数是否和原来的相同,如果相同,则什么都不做,如果不同则进行重新赋值,并在赋值前给mPrivateFlags中添加DRAWN标识,同时调用invalidate()通知View系统原来占用的位置需要重绘。
c) 调用onLayout(),View中定义的onLayout()方法默认什么都不做,View系统提供onLayout()方法的目的是为了使系统包含的子视图的父视图能够在onLayout()方法对子视图进行位置分配,正因为如此,如果是父视图,则必须重写onLayout(),也正因为如此ViewGroup类才会把onLayout重载改成了abstract类型。
d)清除mPrivateFlags中的LAYOUT_REQUIRED标识,因为layout操作已经完成。
上面提到的setFrame方法源码如下:
- protected boolean setFrame(int left, int top, int right, int bottom) {
- boolean changed = false;
- if (DBG) {
- Log.d("View", this + " View.setFrame(" + left + "," + top + ","
- + right + "," + bottom + ")");
- }
- if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
- changed = true;
- // Remember our drawn bit
- int drawn = mPrivateFlags & DRAWN;
- // Invalidate our old position
- invalidate();
- int oldWidth = mRight - mLeft;
- int oldHeight = mBottom - mTop;
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- mPrivateFlags |= HAS_BOUNDS;
- int newWidth = right - left;
- int newHeight = bottom - top;
- if (newWidth != oldWidth || newHeight != oldHeight) {
- onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
- }
- if ((mViewFlags & VISIBILITY_MASK) == VISIBLE) {
- // If we are visible, force the DRAWN bit to on so that
- // this invalidate will go through (at least to our parent).
- // This is because someone may have invalidated this view
- // before this call to setFrame came in, therby clearing
- // the DRAWN bit.
- mPrivateFlags |= DRAWN;
- invalidate();
- }
- // Reset drawn bit to original value (invalidate turns it off)
- mPrivateFlags |= drawn;
- mBackgroundSizeChanged = true;
- }
- return changed;
- }
View中的onLayout()方法如下:
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- }
而ViewGroup中的onLayout()方法如下:
- @Override
- protected abstract void onLayout(boolean changed,
- int l, int t, int r, int b);
转载请说明出处:http://blog.csdn.net/ff20081528/article/details/17784911
因为ViewGroup中的onLayout()方法是一个抽象方法,所以下面我们用他的子类LinearLayout中的onLayout()方法来分析。源码如下:
onlayout()方法:
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- if (mOrientation == VERTICAL) {
- layoutVertical();
- } else {
- layoutHorizontal();
- }
- }
layoutVertical()方法源码:
- void layoutVertical() {
- final int paddingLeft = mPaddingLeft;
- int childTop = mPaddingTop;
- int childLeft;
- // Where right end of child should go
- final int width = mRight - mLeft;
- int childRight = width - mPaddingRight;
- // Space available for child
- int childSpace = width - paddingLeft - mPaddingRight;
- final int count = getVirtualChildCount();
- final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
- final int minorGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
- if (majorGravity != Gravity.TOP) {
- switch (majorGravity) {
- case Gravity.BOTTOM:
- // mTotalLength contains the padding already, we add the top
- // padding to compensate
- childTop = mBottom - mTop + mPaddingTop - mTotalLength;
- break;
- case Gravity.CENTER_VERTICAL:
- childTop += ((mBottom - mTop) - mTotalLength) / 2;
- break;
- }
- }
- for (int i = 0; i < count; i++) {
- final View child = getVirtualChildAt(i);
- if (child == null) {
- childTop += measureNullChild(i);
- } else if (child.getVisibility() != GONE) {
- final int childWidth = child.getMeasuredWidth();
- final int childHeight = child.getMeasuredHeight();
- final LinearLayout.LayoutParams lp =
- (LinearLayout.LayoutParams) child.getLayoutParams();
- int gravity = lp.gravity;
- if (gravity < 0) {
- gravity = minorGravity;
- }
- switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.LEFT:
- childLeft = paddingLeft + lp.leftMargin;
- break;
- case Gravity.CENTER_HORIZONTAL:
- childLeft = paddingLeft + ((childSpace - childWidth) / 2)
- + lp.leftMargin - lp.rightMargin;
- break;
- case Gravity.RIGHT:
- childLeft = childRight - childWidth - lp.rightMargin;
- break;
- default:
- childLeft = paddingLeft;
- break;
- }
- childTop += lp.topMargin;
- setChildFrame(child, childLeft, childTop + getLocationOffset(child),
- childWidth, childHeight);
- childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
- i += getChildrenSkipCount(child, i);
- }
- }
- }
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-pdfview`是一个专为Android平台设计的开源库,它允许开发者在Eclipse这样的集成开发环境中集成并实现PDF文件的展示。这个库是基于Java编程语言,使得在Eclipse中使用变得简单而高效。 在Eclipse中使用`...
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-Search-View-Layout.zip,材料设计搜索视图布局,现在在google地图、拨号器等中实现,安卓系统是谷歌在2008年设计和制造的。操作系统主要写在爪哇,C和C 的核心组件。它是在linux内核之上构建的,具有安全性...
对于深入理解RadiusView的工作原理,需要熟悉Android的View体系结构,理解绘图过程,以及如何处理触摸事件和视图状态。 9. 实战应用(Practical Applications): RadiusView可能适用于创建具有统一圆角风格的...
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 ...
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 '...
`Android-CodeView`控件就是为了满足这种需求而设计的,它允许开发者在Android应用中以美观、高亮的方式展示源代码。下面将详细探讨`CodeView`的特性和使用方法。 首先,`CodeView`是一个开源项目,它的主要功能是...
PowerPoint演示文稿AndroidView的工作原理WWW1PPTCOMContents一前言二工作流程三measure过程四layout过程五draw过程一前言11ViewView类是用户界
总的来说,Android-SpinKit为Android开发者提供了一个强大的加载动画库,使得应用的加载过程更加生动有趣,提升了用户交互体验。同时,开源的特性也让开发者有机会学习到自定义动画的实现原理,进一步提升自身的...
"pdfview打开pdf文件,避免android无法通过webview打开pdf文件"这个主题正是关注如何在Android应用中集成PDF阅读功能,特别是在Eclipse环境下。我们将探讨PDFView库的使用方法,以及如何将其集成到Eclipse项目中。 ...
具体来说,如果设置了`android:layout_above="@id/anotherView"`,那么当前视图将被放置在ID为`anotherView`的视图上方。这是一种非常实用的布局方式,尤其是在需要创建垂直堆叠的UI元素时。 #### `android:layout_...
对于自定义Layout,其工作原理与自定义View类似,但更关注子View的布局策略。比如,可以继承自LinearLayout、RelativeLayout等,然后重写onLayout()方法来决定子View的位置。在自定义Layout时,还可以使用...
2) Add the view to your layout XML. implementation 'com.github.hsmnzaydn:imagezoom:1.2.1' 3) Add the view to your layout XML. <com.ozaydin.serkan.com.image_zoom_view.ImageViewZoom android:layou
this is a draggable flow layout lib (android 可拖拽的流布局库) . Sample apk/示例app 特点 1, 类似可拖拽的GridView. 不过gridView 宽度/个数是固定的。 这个布局item宽度是不定的(放不下自动换行)。 2,...
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
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 ...
Custom layout that can rotate it's view Usage In your layout file add <!-- Specify rotate angle here --> Voila! Your layout will be rotated 90 degrees. Download compile 'rongi.rotate-...
"garland-view-android"的实现原理可能包括但不限于以下几个方面: 1. **视图动画**:通过自定义视图动画,实现列表间的平滑过渡。这可能涉及到帧动画、属性动画等Android系统提供的动画机制,通过精心设计的动画...
ArrayAdapter<String> adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, options); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView....
1. 下载并导入`android-Support-v7-CardView`库项目到你的工作空间。 2. 将这个库项目设置为“Library”属性,右键点击项目 -> Properties -> Android -> Is Library,勾选上。 3. 参照CardView库项目的`build....