测量View(三):获得测量宽高及真实宽高

测量View(一):创建View并测量 http://www.jianshu.com/p/4fb206b947ee
测量View(二):测量宽高及真实宽高 http://www.jianshu.com/p/18540e62ae3a

现在我们可以解决在 测量View(一):创建View并测量 中的问题了

调用View的measure 及 layout方法便可获得测量宽高及真实宽高

方法1:View.post()

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);

        //将View加到根视图中
        mRoot.addView(view);

        int width = view.getWidth();
        int height = view.getHeight();
        int measuredWidthAndState = view.getMeasuredWidthAndState();
        int measuredWidth = view.getMeasuredWidth();
        int measuredHeight = view.getMeasuredHeight();
        int measuredHeightAndState = view.getMeasuredHeightAndState();
    }
测量View(三):获得测量宽高及真实宽高_第1张图片
Paste_Image.png

结果怎么还是0.

查看addView()代码:

public void addView(View child, int index, LayoutParams params) {
       ...
        requestLayout();
       ...
    }

之前学习自定义View时,认为父布局requestLayout后会重新遍历子布局的measure及layout方法
既然调用了measure, layout方法,为何获取不到测量的宽高,真实的宽高。

以下这篇分析了requestLayout方法
http://www.jianshu.com/p/effe9b4333de
简单说就是调用requestLayout后,遍历子布局的操作是在分线程进行的。

知道了原因,上代码

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);

        mRoot.addView(view);

        view.post(new Runnable() {
            @Override
            public void run() {
                int width = view.getWidth();
                int height = view.getHeight();
                int measuredWidthAndState = view.getMeasuredWidthAndState();
                int measuredWidth = view.getMeasuredWidth();
                int measuredHeight = view.getMeasuredHeight();
                int measuredHeightAndState = view.getMeasuredHeightAndState();
            }
        });
  }
测量View(三):获得测量宽高及真实宽高_第2张图片
Paste_Image.png

问题解决

方法2:onWindowFocusChanged()

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);
        mRoot.addView(view);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        int width = view.getWidth();
        int height = view.getHeight();
        int measuredWidthAndState = view.getMeasuredWidthAndState();
        int measuredWidth = view.getMeasuredWidth();
        int measuredHeight = view.getMeasuredHeight();
        int measuredHeightAndState = view.getMeasuredHeightAndState();
    }

onWindowFocusChanged()方法在View的onSizeChanged()后调用。此时View的宽高都已确认
此时获得宽高肯定没问题。

测量View(三):获得测量宽高及真实宽高_第3张图片
Paste_Image.png

方法3:onClick()中获得宽高

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);
        mRoot.addView(view);

        mRoot.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int width = view.getWidth();
                int height = view.getHeight();
                int measuredWidthAndState = view.getMeasuredWidthAndState();
                int measuredWidth = view.getMeasuredWidth();
                int measuredHeight = view.getMeasuredHeight();
                int measuredHeightAndState = view.getMeasuredHeightAndState();
            }
        });
    }
测量View(三):获得测量宽高及真实宽高_第4张图片
Paste_Image.png

没毛病,以上三种方法都是打时间差

方法4 网上有一种方法:手动measure()

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);
        mRoot.addView(view);
        view.measure(0, 0);
        int width = view.getWidth();
        int height = view.getHeight();
        int measuredWidthAndState = view.getMeasuredWidthAndState();
        int measuredWidth = view.getMeasuredWidth();
        int measuredHeight = view.getMeasuredHeight();
        int measuredHeightAndState = view.getMeasuredHeightAndState();
    }

这里的mesure(0, 0)相当于:

        int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);//0
        int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);//0
        view.measure(widthSpec, heightSpec);

但是sorry,结果还是0

测量View(三):获得测量宽高及真实宽高_第5张图片
Paste_Image.png

查看原代码:调用了View的onMeasure()方法

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

getSuggestedMinimumWidth()

    protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }

getSuggestedMinimumHeight()

    protected int getSuggestedMinimumHeight() {
        return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());

    }

以上发现View的宽高与mMinWidth 及 背景的宽高有关系

修改代码:

设置最小宽高
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);

        view.setMinimumWidth(100);
        view.setMinimumHeight(200);

        mRoot.addView(view);

        view.measure(0, 0);
        int width = view.getWidth();
        int height = view.getHeight();
        int measuredWidthAndState = view.getMeasuredWidthAndState();
        int measuredWidth = view.getMeasuredWidth();
        int measuredHeight = view.getMeasuredHeight();
        int measuredHeightAndState = view.getMeasuredHeightAndState();
    }
测量View(三):获得测量宽高及真实宽高_第6张图片
Paste_Image.png
设置背景图片

(1)png图片

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);

        //drawable-mdpi中的png图片48 * 48
        view.setBackgroundResource(R.drawable.ic_launcher);
        mRoot.addView(view); //加不加都行

        Drawable background = view.getBackground();
        int intrinsicWidth = background.getIntrinsicWidth();
        int intrinsicHeight = background.getIntrinsicHeight();
       

        view.measure(0, 0);
        int width = view.getWidth();
        int height = view.getHeight();
        int measuredWidthAndState = view.getMeasuredWidthAndState();
        int measuredWidth = view.getMeasuredWidth();
        int measuredHeight = view.getMeasuredHeight();
        int measuredHeightAndState = view.getMeasuredHeightAndState();
    }
测量View(三):获得测量宽高及真实宽高_第7张图片
Paste_Image.png

(2)xml自定义Drawable

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);

//        drawable-mdpi中自定义的GradientDrawable
//        
//        
//               
//               
//        
        view.setBackgroundResource(R.drawable.bitmap);
        mRoot.addView(view); //加不加都行

        Drawable background = view.getBackground();
        int intrinsicWidth = background.getIntrinsicWidth();
        int intrinsicHeight = background.getIntrinsicHeight();
        
        view.measure(0, 0);
        int width = view.getWidth();
        int height = view.getHeight();
        int measuredWidthAndState = view.getMeasuredWidthAndState();
        int measuredWidth = view.getMeasuredWidth();
        int measuredHeight = view.getMeasuredHeight();
        int measuredHeightAndState = view.getMeasuredHeightAndState();
    }
测量View(三):获得测量宽高及真实宽高_第8张图片
Paste_Image.png

(3)代码定义ShapeDrawable

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRoot = (LinearLayout) findViewById(R.id.root);

        view = new View(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(300, 300);
        view.setLayoutParams(layoutParams);

        ShapeDrawable drawable = new ShapeDrawable();
        drawable.setIntrinsicHeight(100);
        drawable.setIntrinsicWidth(100);

        view.setBackgroundDrawable(drawable);
        mRoot.addView(view);//加不加都可以

        Drawable background = view.getBackground();
        int intrinsicWidth = background.getIntrinsicWidth();
        int intrinsicHeight = background.getIntrinsicHeight();
       
        view.measure(0, 0);
        int width = view.getWidth();
        int height = view.getHeight();
        int measuredWidthAndState = view.getMeasuredWidthAndState();
        int measuredWidth = view.getMeasuredWidth();
        int measuredHeight = view.getMeasuredHeight();
        int measuredHeightAndState = view.getMeasuredHeightAndState();
    }
测量View(三):获得测量宽高及真实宽高_第9张图片
Paste_Image.png

测试手机当前的density为3.0 densityDpi为480

手动测量得到测量的宽高,而真实的宽高都是0,没毛病

注意:所有的View在measure()时都与最小宽高及背景有关吗?答案是否.要看具体的View中onMeasure()方法的定义

以上measure方法可以将View加到主布局中,也可以不加,都可以获得测量宽高

你可能感兴趣的:(测量View(三):获得测量宽高及真实宽高)