获取View宽高的四种方式(避免获取的为0)

前言

在Activity获取控件宽高时,有时获取的为0,无法获取正确的信息,原因是View的measure过程和Activity的生命周期不是同步的,也就是说在Activity走了onCreate、onStart、onResume周期后,并不一定View能测绘完成。

解决方式

  1. onWindowFocusChanged方法中做监听
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus){
            int width = txt.getMeasuredWidth();
            int height = txt.getMeasuredHeight();
            Log.e("测试","onWindowFocusChanged: "+width+"---"+height);
        }
    }

此方法,在Activity失去或者获取到焦点时,会多次调用。

  1. 采用post方法
//txt是一个view
 txt.post(new Runnable() {
            @Override
            public void run() {
                int width = txt.getMeasuredWidth();
                int height = txt.getMeasuredHeight();
                Log.e("测试","post: "+width+"---"+height);
            }
        });

post将一个Runnable放到消息队列中,运行在UI线程中,此Runnable所在的队列,会在view被attached时,进行调用,所以此时,view已经初始化好。

  1. ViewTreeObserver方式
 ViewTreeObserver observer = txt.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                txt.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = txt.getMeasuredWidth();
                int height = txt.getMeasuredHeight();
                Log.e("测试","ViewTreeObserver: "+width+"---"+height);
            }
        });

当视图树的状态发生改变或者视图的可见性发生改变,onGlobalLayout将会被回调,此监听会多次回调,所以要及时注销监听。

  1. view.measure(int widthMeasureSpec, int heightMeasureSpec) 手动测量
 private void measuWidthHeight(){
		//具体值
        int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY);
        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY);
        //wrap_content
       //        int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) -1, View.MeasureSpec.AT_MOST);
//        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) -1, View.MeasureSpec.AT_MOST);
        txt.measure(widthMeasureSpec,heightMeasureSpec);

        Log.e("测试","post: "+txt.getMeasuredWidth()+"---"+txt.getMeasuredHeight());
    }

对于match_parent来说,是无法进行测量的,因为此时无法知道父容器的剩余空间。

附录

View的MesaureSpec创建规则表
获取View宽高的四种方式(避免获取的为0)