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

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

 

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

​
public class MainActivity extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		TextView textView = (TextView) findViewById(R.id.tv);

		int width = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
		int height = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
		textView.measure(width, height);
		height = textView.getMeasuredHeight();
		width = textView.getMeasuredWidth();
		Log.d("chenys", "宽测量px:" + width + " 高测量px" + height);
	}
}

​

运行的结果如下:

 

为什么测量后的结果是这样呢,这与我们布局中定义的200dp宽和30dp的高貌似怎么看都没有关联啊.
我们先通过设备密度值将测量出来的宽高px值转成dp值再来分析,可通过如下方法,将px值转成dp值:

​
public int convertPx2Dp(int px) {
    float density= this.getResources().getDisplayMetrics().density;
    return (int)(px / density+ 0.5F * (float)(px >= 0.0F?1:-1));
}

​

具体代码如下:

​
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView) findViewById(R.id.tv);

        int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        int height = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        textView.measure(width, height);
        height=textView.getMeasuredHeight();
        width=textView.getMeasuredWidth();
        Log.d("chenys",   "宽测量px:" + width+" 高测量px:" + height);
        //px->dp
        int widthDp = convertPx2Dp(width);
        int heightDp = convertPx2Dp(height);
        Log.d("chenys", "测量宽度值转dp值:" + widthDp + " 测量高度值转成dp值:" + heightDp);
}

    public int convertPx2Dp(int px) {
        float density= this.getResources().getDisplayMetrics().density;
        return (int)(px / density+ 0.5F * (float)(px >= 0.0F?1:-1));
    }
}

​

我们来看看转成dp后打印的结果如下:

发现,算出来的dp值还是与布局文件中定义的200dp宽和30dp的高有差距呀.这是怎么回事呢?先不急着解释,我们将计算出来的宽高dp值填写到布局文件的TextView上,先看效果:

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

 

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView) findViewById(R.id.tv);

        int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        int height = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        textView.measure(width, height);
        height=textView.getMeasuredHeight();
        width=textView.getMeasuredWidth();
        Log.d("chenys",   "宽测量px:" + width+" 高测量px:" + height);
        //px->dp
        int widthDp = convertPx2Dp(width);
        int heightDp = convertPx2Dp(height);
        Log.d("chenys", "测量宽度值转dp值:" + widthDp + " 测量高度值转成dp值:" + heightDp);

        //应用测量值,注意:代码设置的话只能传入px值
        textView.setLayoutParams(new RelativeLayout.LayoutParams(width,height));
    }

    public int convertPx2Dp(int px) {
        float density = getResources().getDisplayMetrics().density;
        return (int) (px /density +0.5f);
    }
}

再来看看手机的运行效果:

可以到,很完美的显示出来了.由此,我们还可以得出的结论是:如果代码和布局都对控件设置了宽高值的话,最后是取决于代码中设置的.也就是代码设置的优先应用.


2.通过代码获取布局文件中定义的宽高值
主要是通过下面方法来获取,注意获取到的宽高值是px值来的,该px值就是布局文件中的dp值转成后的值,这个转成有Android系统内部实现.
getLayoutParams().getWidth()和getLayoutParams().getHeight()
布局文件还是刚刚的布局文件:

代码如下:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView) findViewById(R.id.tv);

        int width = textView.getLayoutParams().width;//px
        int height = textView.getLayoutParams().height;
        Log.d("chenys", "TextView的宽px" + width + " TextView的高px" + height);
        int widthDp = convertPx2Dp(width);
        int heightDp = convertPx2Dp(height);
        Log.d("chenys", "TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);
}


运行的结果:

从结果中可以看出来,我们是通过上面的方法,是可以获取到我们之前定义在布局文件中的宽高值的.只不过需要我们进行px->dp的转换才能看到效果而已.
3.通过getWidth()和getHeight()方法直接获取控件的宽高
布局文件还是那个布局文件,这里就不贴图了.
看代码:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = (TextView) findViewById(R.id.tv);

        int width = textView.getWidth();
        int height = textView.getHeight();
        Log.d("chenys", "TextView的宽px" + width + " TextView的高px" + height);
        int widthDp = convertPx2Dp(width);
        int heightDp = convertPx2Dp(height);
        Log.d("chenys", "TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);
}


运行结果如下:

怎么会那么奇怪呢,居然获取到的值都是0,这是因为在Activity生命周期中,onStart, onResume, onCreate都不是真正visible的时间点,真正的visible时间点是onWindowFocusChanged()函数被执行时。
译注:从onWindowFocusChanged被执行起,用户可以与应用进行交互了,而这之前,对用户的操作需要做一点限制。这个onWindowFocusChanged指的是这个Activity得到或者失去焦点的时候 就会call。也就是说 如果你想要做一个Activity一加载完毕,就触发什么的话 完全可以用这个!!!
如果这个view的长宽很确定不为0的话,那很可能是你过早的调用这些方法,也就是说在这个view被加入到rootview之前你就调用了这些方法,返回的值自然为0.
解决该问题的方法有很多,主要就是延后调用这些方法。可以试着在onWindowFocusChanged()里面调用这些方法,验证时可以获取到View的宽高的。
针对这点,我们可以验证下:

public class MainActivity extends Activity {
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.tv);

        int width = textView.getWidth();
        int height = textView.getHeight();
        Log.d("chenys", "onCreate->TextView的宽px" + width + " TextView的高px" + height);
        int widthDp = convertPx2Dp(width);
        int heightDp = convertPx2Dp(height);
        Log.d("chenys", "onCreate->TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);
    }

    @Override
    protected void onStart() {
        super.onStart();
        int width = textView.getWidth();
        int height = textView.getHeight();
        Log.d("chenys", "onStart->TextView的宽px" + width + " TextView的高px" + height);
        int widthDp = convertPx2Dp(width);
        int heightDp = convertPx2Dp(height);
        Log.d("chenys", "onStart->TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);
    }

    @Override
    protected void onResume() {
        super.onResume();
        int width = textView.getWidth();
        int height = textView.getHeight();
        Log.d("chenys", "onResume->TextView的宽px" + width + " TextView的高px" + height);
        int widthDp = convertPx2Dp(width);
        int heightDp = convertPx2Dp(height);
        Log.d("chenys", "onResume->TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        int width = textView.getWidth();
        int height = textView.getHeight();
        Log.d("chenys", "onWindowFocusChanged->TextView的宽px" + width + " TextView的高px" + height);
        int widthDp = convertPx2Dp(width);
        int heightDp = convertPx2Dp(height);
        Log.d("chenys", "onWindowFocusChanged->TextView的宽dp" + widthDp + " TextView的高dp" + heightDp);
    }

    public int convertPx2Dp(int px) {
        float density = getResources().getDisplayMetrics().density;
        return (int) (px / density + 0.5f);
    }

}


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

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值