Android中getWidth()和getMeasureWidth()的区别探究
来源:互联网 发布:mac 谷歌浏览器 utf 8 编辑:程序博客网 时间:2024/05/16 09:53
背景
在Android中正确获得View控件的宽和高——使用篇中我们知道了,getWidth和getMeasureWidth都可以获得view的宽,高同理。
那这两个函数究竟有什么区别呢?其实以前我只是知道获取宽高要那样子,也不知道这两个并不知道这两个函数的区别,所以探究了一下。先看个例子。
例子
我直接贴代码:
使用自定义的View:
public class MyView extends View { private static final String TAG = MyView.class.getSimpleName(); public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.d(TAG, "======>"+"onMeasure") ; printWH(); } private void printWH() { Log.d(TAG,"getMeasuredWidth:"+getMeasuredWidth()); Log.d(TAG,"getMeasuredHeight:"+getMeasuredHeight()); Log.d(TAG,"getWidth:"+getWidth()); Log.d(TAG,"getHeight:"+getHeight()); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Log.d(TAG,"======>"+"onLayout") ; printWH(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.d(TAG,"======>"+"onDraw") ; printWH(); }}
再Activity中使用自定义的View:
public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MyView(this)); Log.d(TAG, "onCreate") ; }}
见证奇迹的时刻:
看到了不一样的地方了吧。
原因
源码对比
public final int getWidth() { return mRight - mLeft;}
public static final int MEASURED_SIZE_MASK = 0x00ffffff;public final int getMeasuredWidth() { return mMeasuredWidth & MEASURED_SIZE_MASK;}
这两个的源码都很简单,大家应该都能看懂,第二个其实就是因为mMeasuredWidth中前面的8位是状态位,后边的是大小,MEASURED_SIZE_MASK可以过滤出大小。
mMeasuredWidth源码追踪
我们查找mMeasuredWidth赋值的地方。
private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;}
然后我们找到使用setMeasuredDimensionRaw的地方:
public final void measure(int widthMeasureSpec, int heightMeasureSpec) { //两个参数是由parent提供的 boolean optical = isLayoutModeOptical(this); if (optical != isLayoutModeOptical(mParent)) { Insets insets = getOpticalInsets(); int oWidth = insets.left + insets.right; int oHeight = insets.top + insets.bottom; widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); } //将两个参数合并到一个key当中 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT || widthMeasureSpec != mOldWidthMeasureSpec || heightMeasureSpec != mOldHeightMeasureSpec) { // first clears the measured dimension flag mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; resolveRtlPropertiesIfNeeded(); int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 : mMeasureCache.indexOfKey(key); if (cacheIndex < 0 || sIgnoreMeasureCache) { // 测绘自己 onMeasure(widthMeasureSpec, heightMeasureSpec); ... } else { long value = mMeasureCache.valueAt(cacheIndex); // 这里使用了我们上面找到的函数,一直追踪可以看到和传入参数的转化过程,我就不详细分析了。我们感兴趣的事这个measure函数 setMeasuredDimensionRaw((int) (value >> 32), (int) value); ... } ... } ... } ...}
其实差别的根本就和measure函数有很大的关系。我们看一下这个函数的介绍:
This is called to find out how big a view should be. The parent supplies constraint information in the width and height parameters.
这个函数就是用来找出这个view究竟应该是多大。他的参数信息是由他的parent提供的。
mRight源码追踪
看完上面的,我们再来追踪一下getWidth()函数中参数的代码。因为有了上面的经验,我们想我们大概也能猜个八九不离十。View中应该也有一个layout()函数。
我们查找一下调出源码:
public void layout(int l, int t, int r, int b) { if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } //前面的我们先不管,这里先存起之前的数据,用来比较是否有改变 int oldL = mLeft; int oldT = mTop; int oldB = mBottom; int oldR = mRight; // 这里有两个函数,setOpticalFrame(l, t, r, b),setFrame(l, t, r, b)我们去查看一下 boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { //在此处调用的onLayout; onLayout(changed, l, t, r, b); mPrivateFlags &= ~PFLAG_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 &= ~PFLAG_FORCE_LAYOUT; mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;}
setOpticalFrame(l, t, r, b)最终也是调用的setFrame(l, t, r, b),我们就直接看这个函数就行了。
protected boolean setFrame(int left, int top, int right, int bottom) { boolean changed = false; ... if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { changed = true; // Remember our drawn bit int drawn = mPrivateFlags & PFLAG_DRAWN; int oldWidth = mRight - mLeft; int oldHeight = mBottom - mTop; int newWidth = right - left; int newHeight = bottom - top; boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); // Invalidate our old position invalidate(sizeChanged); // 这里给我们的mLeft,mTop,mRight,mBottom, mLeft = left; mTop = top; mRight = right; mBottom = bottom; mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); ... } return changed;}
这下知道区别了吧。而view的绘制过程是measure->layout->draw的过程。
所以我们在三个回调中输出,才看出了区别产生了不同的结果。
- Android中getWidth()和getMeasureWidth()的区别探究
- android中getMeasureWidth()和getWidth()方法的区别
- Android自定义控件中getWidth()和getMeasureWidth()的区别
- Android自定义控件中getWidth()和getMeasureWidth()的区别
- getWidth和getMeasureWidth区别
- 浅谈getWidth()和getMeasureWidth()区别
- getWidth()与getMeasureWidth()的区别
- 关于getRawX和getX、getMeasureWidth和getWidth之间的区别
- Android中getWidth和getMeasuredWidth的区别
- Android中getwidth和getmeasuredwidth的区别
- [例证]浅谈getWidth()和getMeasureWidth()区别
- Android View中onSave(),onRestore(),getWidth(),getMeasureWidth()方法解析
- Android中View窗体getWidth和getMeasuredWidth的区别
- android中getWidth()和getMeasuredWidth()之间的区别
- android中getWidth()和getMeasuredWidth()之间的区别
- android中getWidth()和getMeasuredWidth()之间的区别
- Android getWidth和getMeasuredWidth的区别
- getWidth与getMeasureWidth
- 怎么获得属性表的一个属性项的值
- HDU2256(矩阵)
- “黑马程序员” TreeSet
- Latex安装与公式编辑小结
- iOS程序员面试要注意的几个问题~
- Android中getWidth()和getMeasureWidth()的区别探究
- bfc样式控制
- java并发编程:volatile关键字解析
- [IOS]如何在Storyboard中设置Round Rect Button的外边距?
- 破解md5的python代码,持续更新
- UITouch
- 4.Python进阶_函数参数的对应
- hdu 5451(矩阵 +Fibonacci )
- 源码分析Mms--AndroidManifest.xml分析