博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个 forceLayout() 和 requestLayout() 的测试
阅读量:5269 次
发布时间:2019-06-14

本文共 9001 字,大约阅读时间需要 30 分钟。

两个view:

一个是系统默认的FrameLayout,  A

一个是自己自定义的MyView extends View,重载了onMeasure函数(): B

 

[html]
 
  1. @Override  
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.     // TODO Auto-generated method stub  
  4.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  5.     // Log.e(TAG, "onMeasure " + MeasureSpec.getSize(widthMeasureSpec)  
  6.     //      + " " + MeasureSpec.getSize(heightMeasureSpec));  
  7.     setMeasuredDimension(MeasureSpec.makeMeasureSpec(mW-=10, MeasureSpec.EXACTLY),  
  8.             MeasureSpec.makeMeasureSpec(mH-=10, MeasureSpec.EXACTLY));  
  9. }  
@Override	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {		// TODO Auto-generated method stub		super.onMeasure(widthMeasureSpec, heightMeasureSpec);		// Log.e(TAG, "onMeasure " + MeasureSpec.getSize(widthMeasureSpec)		// 		+ " " + MeasureSpec.getSize(heightMeasureSpec));		setMeasuredDimension(MeasureSpec.makeMeasureSpec(mW-=10, MeasureSpec.EXACTLY),				MeasureSpec.makeMeasureSpec(mH-=10, MeasureSpec.EXACTLY));	}

逻辑很简单,每次只要B的onMeasure被触发,那么B的尺寸就原来小10.

 

A包含B,

几个测试case: (measure() 是final的,无法覆盖,不过B的measure()应该是每次被调到的)

1. A.requestLayout();                                    不会调用到B.onMeasure() 和 B.onLayout(), 会调用B.layout() (注意连draw()都没有被调到,这意味着B被A认为完全没变,不需要重绘)

2. B.forceLayout(); A.requestLayout()           会调用到B的.onMeasure() 和 onLayout() 以及 layout(), draw(), onDraw()

3. B.requestLayout()                                      会调用到B的.onMeasure() 和 onLayout() 以及 layout(),draw(), onDraw()

4. B.invalidate()                                               B的layout(), onLayout() 和 onMeasure() 没有被调到,只有 draw() 和 onDraw() 被调到.

5  A.invalidate()                                               B的所有函数都不会被调到.

 

这个结果也符合code的逻辑,forceLayout()如果注释说的一样,是在下一次layout bypass 的过程(自己不会发起一次layout bypass)中,会强制的重新onMeasure和onLayout()

而requestLayout() 除了干forceLayout()的事情将自己的FORCE_LAYOUT标志位设上外,还会发起一次layout pass,

在layout bypass 从 A 传到 B时,虽然 A 的 onMeasure() 和 onLayout() 会调用 B 的 measure() 和 layout(), 但是,因为 B的layout状态没有什么改变,因此

onMeasure()和 onLayout()不会被调用.

在当前4.4的code:

 

[html]
 
  1. public void forceLayout() {  
  2.      ................................................  
  3.         mPrivateFlags |= PFLAG_FORCE_LAYOUT;  
  4.         mPrivateFlags |= PFLAG_INVALIDATED;  
  5.     }  
  6.   
  7. public final void measure(int widthMeasureSpec, int heightMeasureSpec) {  
  8.        ...............................................................  
  9.         if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||  
  10.                .......................................................  
  11.             int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :  
  12.                     mMeasureCache.indexOfKey(key);  
  13.             if (cacheIndex 0 || sIgnoreMeasureCache) {  
  14.                 ..................................................  
  15.                 onMeasure(widthMeasureSpec, heightMeasureSpec);  
  16.                 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;  
  17.             } else {  
  18.                 long value = mMeasureCache.valueAt(cacheIndex);  
  19.                 // Casting a long to int drops the high 32 bits, no mask needed  
  20.                 setMeasuredDimension((int) (value >> 32), (int) value);  
  21.                 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;  
  22.             }  
  23. ......................................................................................  
  24.             mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;  
  25.         }  
  26. .............................................................................  
  27. }  
  28.   
  29.   
  30. public void layout(int l, int t, int r, int b) {  
  31.         .....................................................  
  32.         if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {  
  33.             onLayout(changed, l, t, r, b);  
  34.             mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;  
  35.   
  36.            ...................................................................  
  37.         }  
  38.   
  39.         mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;  
  40.         mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;  
  41.     }  
public void forceLayout() {     ................................................        mPrivateFlags |= PFLAG_FORCE_LAYOUT;        mPrivateFlags |= PFLAG_INVALIDATED;    }public final void measure(int widthMeasureSpec, int heightMeasureSpec) {       ...............................................................        if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||               .......................................................            int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :                    mMeasureCache.indexOfKey(key);            if (cacheIndex < 0 || sIgnoreMeasureCache) {                ..................................................                onMeasure(widthMeasureSpec, heightMeasureSpec);                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;            } else {                long value = mMeasureCache.valueAt(cacheIndex);                // Casting a long to int drops the high 32 bits, no mask needed                setMeasuredDimension((int) (value >> 32), (int) value);                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;            }......................................................................................            mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;        }.............................................................................}public void layout(int l, int t, int r, int b) {        .....................................................        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {            onLayout(changed, l, t, r, b);            mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;           ...................................................................        }        mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;        mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;    }

可见forceLayout()可以导致onMeasure() 和 onLayout(). 而requestLayout() 干的事情比forceLayout()只多不少.

View的forceLayout后面一般会紧跟着View的measure(), 这样可以把view的measuredSize 通过 setMeasuredDimension 设上.

而PFLAG_INVALIDATED 这个flag 应该是标记 重绘的。

而requestLayout()/forceLayout() 设置的另一个flag PFLAG_FORCE_LAYOUT,也一定可以在measure()中 将PFLAG_LAYOUT_REQUIRED flag给打上,

而PFLAG_LAYOUT_REQUIRED 则是可以保证了在调用 layout()函数时,onLayout() 函数会被调用到.

 

还有一点,之前没有仔细看, View的measure(A, B) 函数:

 

[html]
 
  1.            如果有PFLAG_FORCE_LAYOUT 或者 本次的measure的尺寸 A, B 和 之前的尺寸不一样  
  2.                if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||  
  3.                 widthMeasureSpec != mOldWidthMeasureSpec ||  
  4.                 heightMeasureSpec != mOldHeightMeasureSpec) {  
  5.   
  6.             ........................................................  
  7.   
  8.             这一步其实是从之前的MeasureCache里找是否存在 和 本次的measure尺寸一致的 cache  
  9.                         int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :  
  10.                     mMeasureCache.indexOfKey(key);  
  11.             如果没有找到,那么就调用onMeasure, 一般来说,调用了onMeasure才能真正的setMeasuredDimension  
  12.                         if (cacheIndex 0 || sIgnoreMeasureCache) {  
  13.                 // measure ourselves, this should set the measured dimension flag back  
  14.                 onMeasure(widthMeasureSpec, heightMeasureSpec);  
  15.                                 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;  
  16.                         } else {  
  17.                                如果找到有cache,那么就将cache的值 设为 setMeasuredDimension  
  18.                                long value = mMeasureCache.valueAt(cacheIndex);  
  19.                                // Casting a long to int drops the high 32 bits, no mask needed  
  20.                                setMeasuredDimension((int) (value >> 32), (int) value);  
  21.                                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;  
  22.                         }  
  23.                  }  
  24.                   
  25.                 ..............................................  
  26.                 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;  
  27.   
  28.                 ..............................................  
  29.                 mOldWidthMeasureSpec = widthMeasureSpec;  
  30.                 mOldHeightMeasureSpec = heightMeasureSpec;  
  31.   
  32.                 mMeasureCache.put(key, ((long) mMeasuredWidth) <32 |  
  33.                       (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension   
如果有PFLAG_FORCE_LAYOUT 或者 本次的measure的尺寸 A, B 和 之前的尺寸不一样               if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||				widthMeasureSpec != mOldWidthMeasureSpec ||				heightMeasureSpec != mOldHeightMeasureSpec) {			........................................................			这一步其实是从之前的MeasureCache里找是否存在 和 本次的measure尺寸一致的 cache                        int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :					mMeasureCache.indexOfKey(key);			如果没有找到,那么就调用onMeasure, 一般来说,调用了onMeasure才能真正的setMeasuredDimension                        if (cacheIndex < 0 || sIgnoreMeasureCache) {				// measure ourselves, this should set the measured dimension flag back				onMeasure(widthMeasureSpec, heightMeasureSpec);                                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;                        } else {                               如果找到有cache,那么就将cache的值 设为 setMeasuredDimension                               long value = mMeasureCache.valueAt(cacheIndex);                               // Casting a long to int drops the high 32 bits, no mask needed                               setMeasuredDimension((int) (value >> 32), (int) value);                               mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;                        }                 }                                ..............................................                mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;                ..............................................                mOldWidthMeasureSpec = widthMeasureSpec;                mOldHeightMeasureSpec = heightMeasureSpec;                mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |                      (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 

这说明调用measure(A, B), 只要尺寸变化,都会影响 MeasuredHeight/Width

借鉴:http://blog.csdn.net/fyfcauc/article/details/41895509

转载于:https://www.cnblogs.com/ldq2016/p/5382023.html

你可能感兴趣的文章
AX 2009 Grid控件下多选行
查看>>
PHP的配置
查看>>
Struts框架----进度1
查看>>
Round B APAC Test 2017
查看>>
MySQL 字符编码问题详细解释
查看>>
Ubuntu下面安装eclipse for c++
查看>>
Windows 2003全面优化
查看>>
格而知之2:UIView的autoresizingMask属性探究
查看>>
我的Hook学习笔记
查看>>
js中的try/catch
查看>>
寄Android开发Gradle你需要知道的知识
查看>>
整理推荐的CSS属性书写顺序
查看>>
ServerSocket和Socket通信
查看>>
css & input type & search icon
查看>>
Octotree Chrome安装与使用方法
查看>>
趣谈Java变量的可见性问题
查看>>
C# 强制关闭当前程序进程(完全Kill掉不留痕迹)
查看>>
ssm框架之将数据库的数据导入导出为excel文件
查看>>
语音识别中的MFCC的提取原理和MATLAB实现
查看>>
验证组件FluentValidation的使用示例
查看>>