getMeasuredWidth()、getLayoutParams().getWidth()、getWidth()的区别

本文介绍在Android中如何通过不同方式获取或设置控件的宽高,包括测量、代码获取及直接使用getWidth和getHeight方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自: http://blog.youkuaiyun.com/mChenys/article/details/45898267

注意:无论哪种方式,在代码中获取的控件的宽高和设置宽高都是以px做为单位.如果要设置dp值,可先将dp值转成px值后再设置.
先来看看布局文件的xml定义的宽高值,以及显示的效果:



方式1:通过测量获取的宽高值
代码如下:

[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);  
  6.         TextView textView = (TextView) findViewById(R.id.tv);  
  7.   
  8.         int width = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);  
  9.         int height = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);  
  10.         textView.measure(width, height);  
  11.         height = textView.getMeasuredHeight();  
  12.         width = textView.getMeasuredWidth();  
  13.         Log.d("chenys""宽测量px:" + width + " 高测量px" + height);  
  14.     }  
  15. }</span>  
运行的结果如下:


为什么测量后的结果是这样呢,这与我们布局中定义的200dp宽和30dp的高貌似怎么看都没有关联啊.
我们先通过设备密度值将测量出来的宽高px值转成dp值再来分析,可通过如下方法,将px值转成dp值:
[java]  view plain  copy
  1. <span style="font-family:Courier New;">public int convertPx2Dp(int px) {  
  2.     float density= context.getResources().getDisplayMetrics().density;  
  3.     return (int)(px / scale + 0.5F * (float)(px >= 0.0F?1:-1));  
  4. }</span>  
具体代码如下:
[java]  view plain  copy
  1. <span style="font-family:Courier New;">public class MainActivity extends Activity {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);  
  6.         TextView textView = (TextView) findViewById(R.id.tv);  
  7.   
  8.         int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);  
  9.         int height = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);  
  10.         textView.measure(width, height);  
  11.         height=textView.getMeasuredHeight();  
  12.         width=textView.getMeasuredWidth();  
  13.         Log.d("chenys",   "宽测量px:" + width+" 高测量px:" + height);  
  14.         //px->dp  
  15.         int widthDp = convertPx2Dp(width);  
  16.         int heightDp = convertPx2Dp(height);  
  17.         Log.d("chenys""测量宽度值转dp值:" + widthDp + " 测量高度值转成dp值:" + heightDp);  
  18. }  
  19.   
  20.     public int convertPx2Dp(int px) {  
  21.         float density= context.getResources().getDisplayMetrics().density;  
  22.         return (int)(px / scale + 0.5F * (float)(px >= 0.0F?1:-1));  
  23.     }  
  24. }</span>  
我们来看看转成dp后打印的结果如下:
发现,算出来的dp值还是与布局文件中定义的200dp宽和30dp的高有差距呀.这是怎么回事呢?先不急着解释,我们将计算出来的宽高dp值填写到布局文件的TextView上,先看效果:


知道答案了吧,通过测量控件的宽高的方式计算出来的宽高是通过子View向其所在的父控件申请子view正常显示时需要占用的宽高,当然这个宽高值不能超过父控件的最大宽高值,细心的话可以发现,右边的预览效果好像是少了一个字母,如果你运行在真机上看到的效果是刚刚好显示完整所有的字母的.这点,大家可以验证,我这边验证了是可以的.
虽然测量的结果是这样,但是如果你在布局文件中指定了layout_width和layout_height的属性值,则TextView显示的效果是根据你在布局文件中的指定的宽高值来定的.
当然,我们计算了控件的宽高值后,还是可以通过代码让其应用我们测量的宽高值的.
先确认下,我已经把布局文件的TextView的宽高值恢复成了200dp的宽和30dp的高,免得产生错觉.


[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);  
  6.         TextView textView = (TextView) findViewById(R.id.tv);  
  7.   
  8.         int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);  
  9.         int height = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);  
  10.         textView.measure(width, height);  
  11.         height=textView.getMeasuredHeight();  
  12.         width=textView.getMeasuredWidth();  
  13.         Log.d("chenys",   "宽测量px:" + width+" 高测量px:" + height);  
  14.         //px->dp  
  15.         int widthDp = convertPx2Dp(width);  
  16.         int heightDp = convertPx2Dp(height);  
  17.         Log.d("chenys""测量宽度值转dp值:" + widthDp + " 测量高度值转成dp值:" + heightDp);  
  18.   
  19.         //应用测量值,注意:代码设置的话只能传入px值  
  20.         textView.setLayoutParams(new RelativeLayout.LayoutParams(width,height));  
  21.     }  
  22.   
  23.     public int convertPx2Dp(int px) {  
  24.         float density = getResources().getDisplayMetrics().density;  
  25.         return (int) (px /density +0.5f);  
  26.     }  
  27. }  
再来看看手机的运行效果:
可以到,很完美的显示出来了.由此,我们还可以得出的结论是:如果代码和布局都对控件设置了宽高值的话,最后是取决于代码中设置的.也就是代码设置的优先应用.


2.通过代码获取布局文件中定义的宽高值
主要是通过下面方法来获取,注意获取到的宽高值是px值来的,该px值就是布局文件中的dp值转成后的值,这个转成有Android系统内部实现.
getLayoutParams().getWidth()和getLayoutParams().getHeight()
布局文件还是刚刚的布局文件:
代码如下:
[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);  
  6.         TextView textView = (TextView) findViewById(R.id.tv);  
  7.   
  8.         int width = textView.getLayoutParams().width;//px  
  9.         int height = textView.getLayoutParams().height;  
  10.         Log.d("chenys""TextView的宽px" + width + " TextView的高px" + height);  
  11.         int widthDp = convertPx2Dp(width);  
  12.         int heightDp = convertPx2Dp(height);  
  13.         Log.d("chenys""TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);  
  14. }  

运行的结果:
从结果中可以看出来,我们是通过上面的方法,是可以获取到我们之前定义在布局文件中的宽高值的.只不过需要我们进行px->dp的转换才能看到效果而已.
3.通过getWidth()和getHeight()方法直接获取控件的宽高
布局文件还是那个布局文件,这里就不贴图了.
看代码:
[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.activity_main);  
  6.         TextView textView = (TextView) findViewById(R.id.tv);  
  7.   
  8.         int width = textView.getWidth();  
  9.         int height = textView.getHeight();  
  10.         Log.d("chenys""TextView的宽px" + width + " TextView的高px" + height);  
  11.         int widthDp = convertPx2Dp(width);  
  12.         int heightDp = convertPx2Dp(height);  
  13.         Log.d("chenys""TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);  
  14. }  

运行结果如下:
怎么会那么奇怪呢,居然获取到的值都是0,这是因为在Activity生命周期中,onStart, onResume, onCreate都不是真正visible的时间点,真正的visible时间点是onWindowFocusChanged()函数被执行时。
译注:从onWindowFocusChanged被执行起,用户可以与应用进行交互了,而这之前,对用户的操作需要做一点限制。这个onWindowFocusChanged指的是这个Activity得到或者失去焦点的时候 就会call。也就是说 如果你想要做一个Activity一加载完毕,就触发什么的话 完全可以用这个!!!
如果这个view的长宽很确定不为0的话,那很可能是你过早的调用这些方法,也就是说在这个view被加入到rootview之前你就调用了这些方法,返回的值自然为0.
解决该问题的方法有很多,主要就是延后调用这些方法。可以试着在onWindowFocusChanged()里面调用这些方法,验证时可以获取到View的宽高的。
针对这点,我们可以验证下:
[java]  view plain  copy
  1. public class MainActivity extends Activity {  
  2.     private TextView textView;  
  3.   
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.activity_main);  
  8.         textView = (TextView) findViewById(R.id.tv);  
  9.   
  10.         int width = textView.getWidth();  
  11.         int height = textView.getHeight();  
  12.         Log.d("chenys""onCreate->TextView的宽px" + width + " TextView的高px" + height);  
  13.         int widthDp = convertPx2Dp(width);  
  14.         int heightDp = convertPx2Dp(height);  
  15.         Log.d("chenys""onCreate->TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);  
  16.     }  
  17.   
  18.     @Override  
  19.     protected void onStart() {  
  20.         super.onStart();  
  21.         int width = textView.getWidth();  
  22.         int height = textView.getHeight();  
  23.         Log.d("chenys""onStart->TextView的宽px" + width + " TextView的高px" + height);  
  24.         int widthDp = convertPx2Dp(width);  
  25.         int heightDp = convertPx2Dp(height);  
  26.         Log.d("chenys""onStart->TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);  
  27.     }  
  28.   
  29.     @Override  
  30.     protected void onResume() {  
  31.         super.onResume();  
  32.         int width = textView.getWidth();  
  33.         int height = textView.getHeight();  
  34.         Log.d("chenys""onResume->TextView的宽px" + width + " TextView的高px" + height);  
  35.         int widthDp = convertPx2Dp(width);  
  36.         int heightDp = convertPx2Dp(height);  
  37.         Log.d("chenys""onResume->TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);  
  38.     }  
  39.   
  40.     @Override  
  41.     public void onWindowFocusChanged(boolean hasFocus) {  
  42.         super.onWindowFocusChanged(hasFocus);  
  43.         int width = textView.getWidth();  
  44.         int height = textView.getHeight();  
  45.         Log.d("chenys""onWindowFocusChanged->TextView的宽px" + width + " TextView的高px" + height);  
  46.         int widthDp = convertPx2Dp(width);  
  47.         int heightDp = convertPx2Dp(height);  
  48.         Log.d("chenys""onWindowFocusChanged->TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);  
  49.     }  
  50.   
  51.     public int convertPx2Dp(int px) {  
  52.         float density = getResources().getDisplayMetrics().density;  
  53.         return (int) (px / density + 0.5f);  
  54.     }  
  55.   
  56. }  

运行的结果如下,由此可以完美验证这个结论

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值