自定义View关于measure流程的基本思路整理

来源:互联网 发布:一年级毕业季网络直播 编辑:程序博客网 时间:2024/06/01 12:29

在《MeasureSpec的简单说明》这篇文章中对android中View的MeasureSpec测量方法做了详细的说明,今天这篇博文就Measure的测量做一个简单的总结。本文着重点在于怎么将android的一般测量规律应用到自己的自定义View中去,同时也算是给指定一个确定的思路。而对这些测量的内部细节不多做说明。

其实对于Measure要分两个具体的情况:

1)如果测量的是一个View,那么通过View这个类带的measure(int widthMeasureSpec, int heightMeasureSpec)方法就可以完成测量过程。

2)如果是ViewGroup的话,需要先完成childView的测量,这是一个递归的过程。根据childView宽和高在做一些其他的处理,比如ListView或者GridView的onMeasure方法。


正如上面所说,view的Measure方法,是调用measureint widthMeasureSpec,int heightMeasureSpec),注意里面的参数,是根据widthSpec/heightSpec来最终确定view的大小的。所说在我们自定义view如果需要测量的话需要先分别获取view的widthSpec和heightSpec(注:为了描述方便下文widthSpec和heightSpec统统用Spec来表示)。如《MeasureSpec的简单说明》所说,获取Spec的方法有两个

a)调用ViewGroup类的getChildMeasureSpec(int spec, int padding, int childDimension) 来获取View的Spec

.通常来说第一个参数传递的是View的parentView的spec。ViewGroupmeasureChild方法可以说是这个方法怎么使用的参考书:

    protected void measureChild(View child, int parentWidthMeasureSpec,                  int parentHeightMeasureSpec) {              final LayoutParams lp = child.getLayoutParams();                    final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,                      mPaddingLeft + mPaddingRight, lp.width);              final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,                      mPaddingTop + mPaddingBottom, lp.height);              //执行child的measure流程              child.measure(childWidthMeasureSpec, childHeightMeasureSpec);       }            

   先获取ViewGroup的Spec即parentSpec,再加上childView的LayoutParams这两个信息,然后调用getChilMeasureSpec获取childView的Spec,既然获取到了Spec了,那么在调用View类的.measure方法把这个Spec交给measure方法处理就是了。

使用案例:ListView对ItemView进行测量的时候获取ItemView的widthSpec就这么个思路,具体在measureScrapChild这个方法里面,相关代码如下:

//获取itemView的LayoutParams   LayoutParams p = (LayoutParams) child.getLayoutParams();     //非空判断if (p == null) {            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();            child.setLayoutParams(p);        }        //省略两行代码//根据父spec+chid的layoutParams        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,                mListPadding.left + mListPadding.right, p.width);

b)通过makeMeasureSpec(int size, int mode)方法来获取View的Spec值

该方法为ViewGroup类的一个静态方法,事实上getChildMeasureSpec这个方法最后也就是调用了makeMeasureSpec!

使用案例:ListView进行测量的时候获取ItemView的heightSpec就是这么个思路,具体在measureScrapChild这个方法里面,相关代码如下:

 int lpHeight = p.height;        int childHeightSpec;        if (lpHeight > 0) {    //根据高度和设定的measureSpec来获取高度spec            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);        } else {            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);        }
通过a或者b说的两个方法获取到View的Spec值之后就可以调用view的measure方法进行view的测量了,具体是使用a还是b,这个倒是根据具体需求具体分析了,没有固定的要求,可根据需求灵活处理之。ListView关于ItemView的测量完整代码如下:
private void measureScrapChild(View child, int position, int widthMeasureSpec) {       //获取itemView的LayoutParams   LayoutParams p = (LayoutParams) child.getLayoutParams();     //非空判断if (p == null) {            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();            child.setLayoutParams(p);        }        //省略两行代码//根据父spec+chid的layoutParams        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,                mListPadding.left + mListPadding.right, p.width);           int lpHeight = p.height;        int childHeightSpec;        if (lpHeight > 0) {    //根据高度和设定的measureSpec来获取高度spec            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);        } else {            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);        }//测量child的宽和个搞        child.measure(childWidthSpec, childHeightSpec);    }

所以上面的对View的测量总的来说其实是很简单的:第一你只需要先获取View的Spec值,而且不需要只要具体的Spec得到的内部细节;第二,调用View的measure值把

得到的Spec传给measure方法即可。当然如果需要的话完全可以调用setMeasureDimension(int width,int height)来确定一个View的宽和高。具体测量的规则,不同的ViewGroup因为布局不同有着不同的测量逻辑,但是总的思路上是不会变化的,但是测量基本上会少不了Spec的计算就是了!

最后关于这个measure的灵活应用的使用案例可参考这篇博客,该篇博客主要就是运用了measureChildren方法对所有的ChildView进行测量,measureChildren方法其实也就是循环调用了measureChild方法而已。


4 0
原创粉丝点击