您的位置:首页 > 移动开发 > Android开发

android动态测量控件

2016-07-05 17:30 555 查看

android动态测量控件

通常在实际开发中,为了适配,我们会把View设置为match_parent或者wrap_content、又或者是设置weight权重来分配宽高,而不是使用具体值。那么就出现一个问题了,如果动态测量View的实际宽高。

测量宽高的API:android提供了两个API来动态获取View的高:

view.getMeasuredHeight()
view.getHeight()


那么这两个API的区别是什么呢?

简单来说就是:

view.getMeasuredHeight() 是由view中的测量方法赋值的,这个值包含了隐藏的高度(比如一个view部分超出屏幕,他也会计算出来)。

view.getHeight() 由view的底部位置减去顶部位置,即实际显示的View的高度,不包含隐藏了的高度。

如果是在View的onMeasure方法后执行上面两个方法,会发现可以得到正确的高度,但是如果是在onCreate等方法中执行就会发现返回的值不正确或者为0,这是为什么呢?

这是因为View的onMeasure()方法在Activity的onCreate();onResume()方法之后执行,此时还没有测量出实际的宽高,还没有进行绘制,所以调用上述的两个API会出现值为0或者数值错误的情况。

测量方法:

1 : 主动请求测量:

view.measure(0, 0);
view.getMeasuredWidth();
view.getMeasuredHeight();


说明:

onMeasure传入的两个参数是由父控件的大小,

也可以使用 View.MeasureSpec.makeMeasureSpec(0,mode);设置值

其中mode可以选择

MeasureSpec.UNSPECIFIED 未指定尺寸,比如listview中尺寸由父控件决定
MeasureSpec.EXACTLY 适合match_parent或者具体值
MeasureSpec.AT_MOST 适合wrap_content不确定值


注意:

这种方法不一定能测出正确的值,因为onMesure会多次调用(由于onMesure自上而下,父控件如果对于子控件的宽高不满意,即如子控件没有限制宽高,父控件会重新调用onMesure重新测量),所以测量结果不一定正确。

2 :使用OnPreDrawListener

ViewTreeObserver observer = view.getViewTreeObserver();
observer.addOnPreDrawListener(new OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
int height = view.getMeasuredHeight();
int width = view.getMeasuredWidth();
return true;
}
});


说明:

这个是异步解决方法,在onDraw之前执行,onDraw方法执行在onMeasure之后,所以这个监听器可以解决动态获取的问题。

注意:

onPreDraw方法只有return true才会生效,由于onDraw会在view绘制时调用,所以可能会调用多次,务必调用removeOnPreDrawListener方法,防止执行效率问题。onDraw会多次执行,每次view出现都会调用,但onLayout不会,测量后会被记录下来。

3.使用OnGlobalLayoutListener

ViewTreeObserver observer = view.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int height = img.getWidth();
int width = img.getHeight();
}
});


说明:

这个也是异步解决方法,在全局onLayout触发时执行。

注意:

这个方法有一定不确定性,而且onLayout执行第一次的数值不一定正确。

4.使用OnLayoutChangeListener

view.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {

}

});


说明:这个方法OnLayout时调用,而且只有改变时才会触发。

注意:这个方法要求API level 11
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: