Android MeasuerSpec的由来及使用

含义:MeasuerSpec是parent传递给child的一组测量值(size)和模式(mode)的组合。

使用场景:经常我们会在child的onMeasure(int widthMeasureSpec,int heightMeasureSpec)这个函数中来对spec进行处理,用于确定child的长和宽。

Android MeasuerSpec的由来及使用_第1张图片

这里我们看到MeasureSpec有3中测量模式:

MeasureSpec.AT_MOST :child最多达到parent的大小,这一类通常归于"wrap_content"。

MeasureSpec.EXACTLY:child的大小是一个确定的值,这一类通常归于"match_parent"或者是一个确定的值。

MeasureSpec.UNSPECIFED:这个几乎不用,未指定,child可以得到自己想要的任何大小。

Measure的makeMeasureSpec,getMode,getSize我这里就不多说了,很简单就是一个位运算。


说了半天,到底这个widthMeasureSpec和heightMeasureSpec怎么来的呢?这就需要看看源码。

我们知道View的测量和绘制都是通过它的parent来触发的,所以直接进ViewGroup

切入点就是measure:

Android MeasuerSpec的由来及使用_第2张图片

这里我们又看到一个parentWidthMeasureSpec和parentHeightSpec,这里我们先不管,大概知道这个是它的parent给它的spec。

继续进入函数:

Android MeasuerSpec的由来及使用_第3张图片

可以看到,这里在switch(mode)和我们处理view的onMeasure差不多。

继续向下:

Android MeasuerSpec的由来及使用_第4张图片

到这里,spec就已经组合好了,下一步应该是传递给child计算了。Android MeasuerSpec的由来及使用_第5张图片

Android MeasuerSpec的由来及使用_第6张图片

到这里为止,viewgroup的测量就算完成了。接下来就是交给child自己计算,也就回到了,我们最初的onMeasure函数中。

上面我们还说到了这个parentWidthMeasureSpec和parentHeightSpec,其实也就是当前viewgroup的parent给它的测量模式和值。遵循上面的步骤,一模一样。


所以以后像遇到这个问题,解决思路和办法就很简单了。

View view=getLayoutInflater().inflate(R.layout.layout_item, null);

Toast.makeText(MainActivity.this, "view_w="+view.getMeasuredWidth()+","+view.getLayoutParams(), 0).show();

Android MeasuerSpec的由来及使用_第7张图片

为啥view的宽度为0,layoutparams为null?

view的宽度为0,很明显:就是view没有measure,因为我们是从一个xml文件中pull解析出来的一个view,它没有parent更没有parent测量,所以为0.

解决办法就是measure,view.measure(0,0)一下;我们传0,0,最终也就是view自己测量自己。这里还有一个layoutparams为null,为啥呢?

我们知道layoutParams是parent给child的布局参数。在view的源码中我们看到

Android MeasuerSpec的由来及使用_第8张图片

还有get,set方法

Android MeasuerSpec的由来及使用_第9张图片

我们回到viewGroup中。


Android MeasuerSpec的由来及使用_第10张图片

这里我们看到addview会传递一个params,这个params怎么来的呢?

Android MeasuerSpec的由来及使用_第11张图片

这里我们看到了child的layoutparams是在addview中赋值的,所以上面的layoutinflate的view因为没有parent所以就没有layoutparams。

解决办法:

Android MeasuerSpec的由来及使用_第12张图片

欢迎大家指正和批评!



你可能感兴趣的:(Android MeasuerSpec的由来及使用)