Android 获取控件的宽度和高度的几种方式

我们知道直接在onCreate中调用getWidth和getMeasuredWidth是获取不到控件的宽度和高度的

原因是:

等onCreate方法执行完了,我们定义的控件才会被度量(measure),所以我们在onCreate方法里面通过view.getHeight()获取控件的高度或者宽度肯定是0,因为它自己还没有被度量,也就是说他自己都不知道自己有多高,而你这时候去获取它的尺寸,肯定是不行的.

以ProgressBar为例:
我们先看看原始控件的宽高:

      <ProgressBar
                android:id="@+id/pb_number"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="match_parent"
                android:layout_height="25dp"

                 />
 再看看我们得到的值:
方法一
width630px
MeasuredWidth630px
Height50px
MeasuredHeight50px
方法2
postwidth630px
postMeasuredWidth630px
postHeight50px
postMeasuredHeight50px          

先说下getWidth和getMeasuredWidth的区别以及两者的使用场景

首先,看getWidth()的官方说明:

public final int getWidth ()

Added in API level 1
Return the width of the your view.

Returns
The width of your view, in pixels.

返回view的宽度,说的不详细,再看getWidth源码:

 * Return the width of the your view. 
     * 
     * @return The width of your view, in pixels. 
     */  
    @ViewDebug.ExportedProperty(category = "layout")  
    public final int getWidth() {  
        return mRight - mLeft;  
    }

从源码可以看出,getwidth返回的是右边坐标减去左边坐标,这要在布局之后才能确定它们的坐标,也就是说在布局后才能调用getwidth来获取。所以getWidth()获得的宽度是View在设定好布局后整个View的宽度。

而对于getmeasuredwidth,我们看看官方解释

public final int getMeasuredWidthAndState ()

Added in API level 11
Return the full width measurement information for this view as computed by the most recent call to measure(int, int). This result is a bit mask as defined byMEASURED_SIZE_MASK and MEASURED_STATE_TOO_SMALL. This should be used during measurement and layout calculations only. Use getWidth() to see how wide a view is after layout.

Returns
The measured width of this view as a bit mask.

得到的是最近一次调用measure()方法测量后得到的是View的宽度,它应该仅仅用在测量和Layout的计算中。再看源码:

/** 
 * Like {@link #getMeasuredWidthAndState()}, but only returns the 
 * raw width component (that is the result is masked by 
 * {@link #MEASURED_SIZE_MASK}). 
 * 
 * @return The raw measured width of this view. 
 */  
public final int getMeasuredWidth() {  
    return mMeasuredWidth & MEASURED_SIZE_MASK;  
}  

获得的是原始的测量宽度。所以说getMeasuredWidth()是对View上的内容进行测量后得到的View内容占据的宽度。

前提是你必须在父布局的onLayout()方法或者此View的onDraw()方法里调用measure(0,0);(measure中的参数的值你自己可以定义),否则你得到的结果和getWidth()得到的结果是一样的。

两者的使用场合:

getMeasuredWidth:
在自定义view重写onLayout时、在我们用layoutinflater动态加载view后想获得view的原始宽度时。

getWidth:
一般在view已经布局后呈现出来了,想获取宽度时

摘自:http://blog.csdn.net/u011494050/article/details/39134161

下面具体说说几种获取的方式吧:

No1:

int w = View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED);
        int h = View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED);
        imageView.measure(w, h);
        int height = imageView.getMeasuredHeight();
        int width = imageView.getMeasuredWidth();

这种方法很简单,就是我们自己来测量

No2:

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

这个方法,我们需要注册一个ViewTreeObserver的监听回调,这个监听回调,就是专门监听绘图的,既然是监听绘图,那么我们自然可以获取测量值了,同时,我们在每次监听前remove前一次的监听,避免重复监听。

No3:

ViewTreeObserver vto = imageView.getViewTreeObserver();   
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
            @Override  
            public void onGlobalLayout() { 
                imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
                imageView.getHeight();
                imageView.getWidth();
            }   
        });

这个方法于第2个方法基本相同,但他是全局的布局改变监听器,所以是最推荐使用的。

总结:那么需要获取控件的宽高该用那个方法呢?

  • 方法一: 比其他的两个方法多了一次计算,也就是多调用了一次onMeasure()方法,该方法虽然看上去简单,但是如果要目标控件计算耗时比较大的话(如listView等),不建议使用.

  • 方法二:它的回调方法会调用很多次,并且滑动TextView的时候任然会调用,所以不建议使用.

  • 方法三:比较合适.
    当然,实际应用的时候需要根据实际情况而定.

再拓展一种比较简单的方法view.post:

            pbNumber.post(new Runnable() {
                    @Override
                    public void run() {
                        Log.v("tag", "postwidth"+pbNumber.getWidth()+"px");
                        Log.v("tag", "postMeasuredWidth"+pbNumber.getMeasuredWidth()+"px");
                        Log.v("tag", "postHeight"+pbNumber.getHeight()+"px");
                        Log.v("tag", "postMeasuredHeight"+pbNumber.getMeasuredHeight()+"px");

                    }
                });

View.post()这个方法一般用来做什么?

我体会最深的有两个作用:

  • 大家都知道在onCreate()方法中调用view.getHeight()会返回0,但是你可以在
  view.post(new Runnable() {
            @Override
            public void run() {
                 MainApp.showToastMsg("" + view.getHeight());
            }
        });

来获取他的高度。

  • 用View.postDelayed()方法来防止段时间内多次点击view而触发多次不必要的点击事件:
 view.setEnabled(false);
 view.postDelayed(new Runnable() {
            @Override
            public void run() {
               view.setEnabled(true); 
            }
        },300);

作为懒人的我,毫不犹豫的选择了view.post方法。
参考:
以上3中方式解释:
http://blog.csdn.net/johnny901114/article/details/7839512
view.post方式的解释
https://segmentfault.com/q/1010000004304827/a-1020000004332087

http://androidperformance.com/2015/12/29/Android%E5%BA%94%E7%94%A8%E5%90%AF%E5%8A%A8%E4%BC%98%E5%8C%96-%E4%B8%80%E7%A7%8DDelayLoad%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%92%8C%E5%8E%9F%E7%90%86-%E4%B8%8B%E7%AF%87.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哆啦A梦z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值