`
djun100
  • 浏览: 167339 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

安卓高手之路之图形系统(6)requestLayout的流程

 
阅读更多

当一个View调用requestLayout的时候,会给当前的View设置一个FORCE_LAYOUT标记。由此向ViewParent请求布局。这样从这个View开始向上一直requestLayout。最终到达ViewRootImpl。ViewParent 就是当前的传输链。【参见职责链设计模式】

第一步。

ViewRootImpl发现请求了布局。那么就会调用measure方法。

measure方法确认当前View是否有FORCE_LAYOUT标记。

如果有,那么就会进行重新measure。并且设置标记LAYOUT_REQUIRED。

Java代码收藏代码
  1. publicfinalvoidmeasure(intwidthMeasureSpec,intheightMeasureSpec){
  2. if((mPrivateFlags&FORCE_LAYOUT)==FORCE_LAYOUT||
  3. widthMeasureSpec!=mOldWidthMeasureSpec||
  4. heightMeasureSpec!=mOldHeightMeasureSpec){
  5. //firstclearsthemeasureddimensionflag
  6. mPrivateFlags&=~MEASURED_DIMENSION_SET;
  7. if(ViewDebug.TRACE_HIERARCHY){
  8. ViewDebug.trace(this,ViewDebug.HierarchyTraceType.ON_MEASURE);
  9. }
  10. //measureourselves,thisshouldsetthemeasureddimensionflagback
  11. onMeasure(widthMeasureSpec,heightMeasureSpec);
  12. //flagnotset,setMeasuredDimension()wasnotinvoked,weraise
  13. //anexceptiontowarnthedeveloper
  14. if((mPrivateFlags&MEASURED_DIMENSION_SET)!=MEASURED_DIMENSION_SET){
  15. thrownewIllegalStateException("onMeasure()didnotsetthe"
  16. +"measureddimensionbycalling"
  17. +"setMeasuredDimension()");
  18. }
  19. mPrivateFlags|=LAYOUT_REQUIRED;
  20. }
  21. mOldWidthMeasureSpec=widthMeasureSpec;
  22. mOldHeightMeasureSpec=heightMeasureSpec;
  23. }

第二步。

在随后的layout方法中,会判断这个标记。如果这个标记为true。

那么就一定会调用onLayout.

onLayout调用后清理LAYOUT_REQUIRED标记。

layout调用之后,会清理掉FORCE_LAYOUT标记。

Java代码收藏代码
  1. @SuppressWarnings({"unchecked"})
  2. publicvoidlayout(intl,intt,intr,intb){
  3. intoldL=mLeft;
  4. intoldT=mTop;
  5. intoldB=mBottom;
  6. intoldR=mRight;
  7. booleanchanged=setFrame(l,t,r,b);
  8. if(changed||(mPrivateFlags&LAYOUT_REQUIRED)==LAYOUT_REQUIRED){
  9. if(ViewDebug.TRACE_HIERARCHY){
  10. ViewDebug.trace(this,ViewDebug.HierarchyTraceType.ON_LAYOUT);
  11. }
  12. onLayout(changed,l,t,r,b);
  13. mPrivateFlags&=~LAYOUT_REQUIRED;
  14. ListenerInfoli=mListenerInfo;
  15. if(li!=null&&li.mOnLayoutChangeListeners!=null){
  16. ArrayList<OnLayoutChangeListener>listenersCopy=
  17. (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
  18. intnumListeners=listenersCopy.size();
  19. for(inti=0;i<numListeners;++i){
  20. listenersCopy.get(i).onLayoutChange(this,l,t,r,b,oldL,oldT,oldR,oldB);
  21. }
  22. }
  23. }
  24. mPrivateFlags&=~FORCE_LAYOUT;
  25. }

当然在上述过程中,影响到了兄弟或者是父亲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的时候无法对其进行通知,这也是这种实现的缺陷。

分享到:
评论

相关推荐

    TestAddView

    addView 源码中。为什么在addViewInner(); 前要使用requestLayout(); addViewInner里面会调用requestLayout(); 这样逻辑上是不是重复了。

    Android ListView嵌套GridView(GridView实现横向滑动)

    Android ListView嵌套GridView(GridView实现横向滑动)

    Android代码-probe

    requestLayout() Override any of these methods on-the-fly. Layout debugging: OvermeasureInterceptor: Tints views according to the number of times they got measured in a single traversal. ...

    Android酷炫转动菜单

    R.drawable.home_mbank_6_normal }; private int mTouchSlop; /** * 加速度检测 */ private float mDownAngle; private float mTmpAngle; private long mDownTime; private boolean isFling; ...

    Android UI绘制流程及原理详解

    一、绘制流程源码路径 1、Activity加载ViewRootImpl ActivityThread.handleResumeActivity() --&gt; WindowManagerImpl.addView(decorView, layoutParams) --&gt; WindowManagerGlobal.addView() 2、ViewRootImpl...

    Android ImageView 不显示JPEG图片的问题解决

    Android ImageView 不显示JPEG图片 今天在写一个小实例,ImageView在xml里面设置的是INVISIBLE,在代码里需要设置成setVisibility(View.VISIBLE),但图片没有显示出来,换成PNG或其它的JPEG格式的图片确可以正常的...

    Android仿即刻首页垂直滚动图,炫酷到底!

    这个效果是在即刻app上看到,觉得很不错,遂仿之。 先说下我的实现思路(以上方的图片滚动为例,下方的文字实现效果类似): 自定义ViewGroup 装载两个ImageView和一个阴影View 通过一定规律交替控制两个ImageView和...

    Android开发重写Animation实现下拉图片后弹射回去效果示例

    本文实例讲述了Android开发重写Animation实现下拉图片后弹射回去效果。分享给大家供大家参考,具体如下: 1. 解析: 1)interpolatedTime指的是平移的变化率(从0到1) 2)mStartHeight 控件开始的高度 3)endHeight...

    3-基础控件1

    84 20.1.4. requestLayout方法 86 20.1.5. invalidate方法 87 20.2. ViewHolder相关 87 20.2

    打造Android微信朋友圈下拉刷新控件

    第三步:在ViewDragHelper的拖动回调方法里面,设置listView和彩虹LoadingView的位置,调用requestLayout。 第四步:手势松开后,开始刷新,LoadingView在固定位置做旋转动画。 第五步:如果设置了onRefreshListener...

    ViewPager 放大缩小左右移动

    实现 图片的放大,缩小,左右屏幕滑动 。 直接贴代码吧。。 public class ViewPager extends ViewGroup { private static final String TAG = "ViewPager"; private static final boolean DEBUG = false;...

Global site tag (gtag.js) - Google Analytics