• 一个 forceLayout() 和 requestLayout() 的测试


    两个view:

    一个是系统默认的FrameLayout,  A

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

    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:

    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) 函数:

    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

  • 相关阅读:
    省市县区镇街道可查询地址
    用代码实现表情包
    如何让input number类型的标签不产生上下加减的按钮
    float类型如何转换为string类型
    php 如何得到不含前导0的时分秒
    项目引入非配置的文件,打成war包后测试报错的可能原因
    Spring Cloud(十四)Config 配置中心与客户端的使用与详细
    Spring Cloud (十三) Zuul:静态路由、静态过滤器与动态路由的实现
    Spring Cloud(十二)声名式服务调用:Feign 的使用(下)
    Spring Cloud(十一)声名式服务调用:Feign的使用 (上)
  • 原文地址:https://www.cnblogs.com/ldq2016/p/5382023.html
Copyright © 2020-2023  润新知