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

来源:互联网 发布:linux分页显示命令 编辑:程序博客网 时间:2024/06/03 15:54

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



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

public class MainActivity extends Activity {@Overrideprotected 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);}}</span>
运行的结果如下:


为什么测量后的结果是这样呢,这与我们布局中定义的200dp宽和30dp的高貌似怎么看都没有关联啊.
我们先通过设备密度值将测量出来的宽高px值转成dp值再来分析,可通过如下方法,将px值转成dp值:
<span style="font-family:Courier New;">public int convertPx2Dp(int px) {    float density= context.getResources().getDisplayMetrics().density;    return (int)(px / scale + 0.5F * (float)(px >= 0.0F?1:-1));}</span>
具体代码如下:
<span style="font-family:Courier New;">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= context.getResources().getDisplayMetrics().density;        return (int)(px / scale + 0.5F * (float)(px >= 0.0F?1:-1));    }}</span>
我们来看看转成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 0
原创粉丝点击