当一个View调用requestLayout的时候,会给当前的View设置一个FORCE_LAYOUT标记。由此向ViewParent请求布局。这样从这个View开始向上一直requestLayout。最终到达ViewRootImpl。ViewParent 就是当前的传输链。【参见职责链设计模式】
第一步。
ViewRootImpl发现请求了布局。那么就会调用measure方法。
measure方法确认当前View是否有FORCE_LAYOUT标记。
如果有,那么就会进行重新measure。并且设置标记LAYOUT_REQUIRED。
public final void measure(int widthMeasureSpec, int heightMeasureSpec) { if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT || widthMeasureSpec != mOldWidthMeasureSpec || heightMeasureSpec != mOldHeightMeasureSpec) { // first clears the measured dimension flag mPrivateFlags &= ~MEASURED_DIMENSION_SET; if (ViewDebug.TRACE_HIERARCHY) { ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_MEASURE); } // measure ourselves, this should set the measured dimension flag back onMeasure(widthMeasureSpec, heightMeasureSpec); // flag not set, setMeasuredDimension() was not invoked, we raise // an exception to warn the developer if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) { throw new IllegalStateException("onMeasure() did not set the" + " measured dimension by calling" + " setMeasuredDimension()"); } mPrivateFlags |= LAYOUT_REQUIRED; } mOldWidthMeasureSpec = widthMeasureSpec; mOldHeightMeasureSpec = heightMeasureSpec; }
第二步。
在随后的layout方法中,会判断这个标记。如果这个标记为true。
那么就一定会调用onLayout.
onLayout调用后清理LAYOUT_REQUIRED标记。
layout调用之后,会清理掉FORCE_LAYOUT标记。
@SuppressWarnings({"unchecked"}) public void layout(int l, int t, int r, int b) { int oldL = mLeft; int oldT = mTop; int oldB = mBottom; int oldR = mRight; 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; ListenerInfo li = mListenerInfo; if (li != null && li.mOnLayoutChangeListeners != null) { ArrayList<OnLayoutChangeListener> listenersCopy = (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); int numListeners = listenersCopy.size(); for (int i = 0; i < numListeners; ++i) { listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); } } } mPrivateFlags &= ~FORCE_LAYOUT; }
当然在上述过程中,影响到了兄弟或者是父亲View的大小, 那么也兄弟或者是父亲View也会调用layout/onLayout。不管其是否已经调用requestLayout。如果说指定的MeasureSpec为此也发生了变化,
那么measure/onMeasure也会被调用。
通过上述分析发现,只要调用了requestlayout, 那么measure和onMeasure,以及layout,onlayout,draw onDraw都会被调用。
在很多情况下,requestLayout是不需要被调用的。例如,我们把一个AbsoluteLayout里面的childView挪动一下位置。我们仅仅需要调用的可能就是重新布局当前AbsoluteLayout,然后调用invalidate方法进行重绘。而不是从当前View向上的整个View树形结构都要重新layout,onLayout,measure,onMeasure一次。
这个时候,怎么办?
一种方法是,直接调用onLayout。然后调用invalidate进行重绘。很明显可以提升绘制效率。由于父View的layout实现中对会通知布局的listener。但是由于无法得到listener,因此调用onlayout的时候无法对其进行通知,这也是这种实现的缺陷。
相关推荐
"安卓动态控制叠放层级"的主题涉及到如何在运行时改变Android应用中不同视图控件的层级顺序。下面我们将深入探讨这一主题。 首先,理解Android中的ViewGroup是至关重要的。ViewGroup是Android UI布局的基础,它是一...
在Android开发中,有时我们需要创建可以拖动的视图,比如浮动窗口或者可移动的控件,这时就涉及到了`ViewDragHelper`的使用。`ViewDragHelper`是Android SDK提供的一种工具类,用于帮助开发者处理View的拖放操作,它...
【标题】"安卓Android源码——(鼠标关节拖拽Body)" 涉及的是在Android平台上实现的一种交互功能,即通过鼠标(或触摸屏)的关节拖拽操作来控制Body对象(通常指的是UI元素或者游戏中的角色)。这个功能在开发过程中...
本资源"安卓Android源码——MyEditText1.rar"提供了一个自定义编辑框(EditText)的示例,让我们来深入探讨这个自定义控件`MyEditText1`的相关知识点。 1. **自定义控件基础** 自定义控件通常是为了满足特定需求或...
本压缩包提供的"安卓Android源码——android平台仿pinterest瀑布流展现方式实现.rar",旨在帮助开发者理解和实践这种布局的实现方法。以下是关于这一主题的详细知识讲解。 首先,我们需要了解瀑布流布局的基本原理...
在Android开发中,SurfaceView是一种特殊的视图,它允许开发者创建高性能的图形界面,尤其适合处理视频播放或游戏等需要连续刷新的场景。本话题主要探讨如何利用SurfaceView实现图片的缩放和滑动功能。 首先,理解...
本教程将通过一个名为“安卓Android源码——更换软件主题(apk方式)”的示例项目,深入讲解如何在Android应用中实现主题更换。 首先,我们来理解主题的概念。在Android中,主题是通过样式(Style)和主题资源...
addView 源码中。为什么在addViewInner(); 前要使用requestLayout(); addViewInner里面会调用requestLayout(); 这样逻辑上是不是重复了。
这个“安卓Android源码——换肤.zip”文件很可能是提供了一套完整的源代码示例,帮助开发者了解如何在Android应用中实现实时换肤。 首先,我们需要理解换肤的基本原理。在Android应用中,换肤主要是通过替换资源...
本文将基于提供的“Android开发之google源码——图片拖拽效果的实现”资源,深入探讨如何在Android平台上创建这样的功能。 首先,我们要理解图片拖拽效果的核心原理。这种效果通常依赖于触摸事件(MotionEvent)的...
用户手动调用`requestLayout()`或`invalidate()`只会触发measure和layout(如果需要)或者draw(如果已知尺寸和位置),并不会触发完整的绘制流程。 了解和掌握这些知识对于优化Android UI性能和开发自定义View组件...
在Android中,自定义View允许开发者根据自己的需求扩展系统提供的基础视图,实现个性化的效果。这里的六边形View是一个自定义组件,它继承自Android的基础View类,并且覆盖了必要的方法来绘制六边形形状。开发者可以...
在Android应用开发中,用户界面的设计是至关重要的,而按钮(Button)作为用户与应用交互的主要元素之一,其样式和功能的定制化需求尤为突出。"一个有单击效果的圆button"项目正是针对这种需求提供的一种解决方案,...
在"安卓Android源码——多个按钮左右相互挤压效果demo.rar"这个压缩包中,我们很可能会找到一个演示如何实现这一功能的源代码项目。下面将详细解释这种效果的实现原理及其相关知识点。 首先,我们需要理解Android...
在Android系统中,RelativeLayout是一个布局管理器,允许视图根据它们与其他视图的关系进行相对定位。通过继承RelativeLayout,DragView保留了其灵活性,并在此基础上添加了拖放功能。这意味着开发者可以在拖动过程...
本示例代码是针对"android手势移动代码(动态图片跟随手势移动)",主要用于实现动态图片跟随用户的触摸手势进行移动,这对于游戏开发或是任何需要图形对象移动的应用都极其有用。下面我们将详细讲解这一技术。 ...
本项目“安卓Android源码——拖动 Button 显示效果”旨在展示如何通过自定义视图(View)和手势检测来实现拖动按钮并产生特定视觉反馈的效果。下面将详细讲解这个知识点。 1. **自定义 View** 在Android中,我们...
在Android开发中,TextView是用于显示单行或多行文本的常用组件。然而,有时我们希望在用户点击时,TextView的内容能以动画效果展开或收缩,为用户提供更好的交互体验。本教程将详细介绍如何实现一个没有使用...
在Android开发中,自定义组合控件是一种常见的需求,它允许开发者根据项目需求创建具有独特功能和视觉效果的用户界面...通过不断实践和学习,开发者可以更好地理解和利用Android系统的灵活性,打造出独具特色的应用。
可以使用`requestLayout()`方法通知系统布局需要更新。 4. **文字居中对齐**: 在矩形内使文本居中显示,可以设置TextView的`gravity`属性为`Gravity.CENTER`,这样文本会沿水平和垂直方向居中。 5. **文字大小的...