getHeight,getWidth,getMeasuredHeight,getMeasureWidth

1 获取View的宽高

简单布局,获取宽高:

 <LinearLayout
      android:id="@+id/view_group_demo"
      android:layout_width="match_parent"
      android:layout_height="100dp"
      android:orientation="vertical">
      <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="sjldjflsjfljs"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="sjldjflsjfljs"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="sjldjflsjfljs"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="sjldjflsjfljs"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="sjldjflsjfljs"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="sjldjflsjfljs"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="sjldjflsjfljs"/>
  </LinearLayout>

Activity文件:

public class Main15Activity2 extends AppCompatActivity {

    private LinearLayout mGroupDemo;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main15);
        mGroupDemo = findViewById(R.id.view_group_demo);
        System.out.println("=============onCreate================="+mGroupDemo.getWidth()+"     "+mGroupDemo.getHeight());
        System.out.println("=============onCreate================="+mGroupDemo.getMeasuredWidth()+"     "+mGroupDemo.getMeasuredHeight());
    }

    @Override
    protected void onStart() {
        super.onStart();
        System.out.println("=============onStart================="+mGroupDemo.getWidth()+"     "+mGroupDemo.getHeight());
        System.out.println("=============onStart================="+mGroupDemo.getMeasuredWidth()+"     "+mGroupDemo.getMeasuredHeight());
    }

    @Override
    protected void onResume() {
        super.onResume();
        System.out.println("=============onResume================="+mGroupDemo.getWidth()+"     "+mGroupDemo.getHeight());
        System.out.println("=============onResume================="+mGroupDemo.getMeasuredWidth()+"     "+mGroupDemo.getMeasuredHeight());
    }
}

结果:
=onCreate=0 0
=onCreate
=0 0
=onStart=0 0
=onStart
=0 0
=onResume=0 0
=onResume
=0 0
发现所有的结果都是0,如何获取呢?
可以获取的方法举例:

//这个是网上找到的方法,但是发现有时黑屏情况下获取到的值为0
 @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus){
            System.out.println("=============onWindowFocusChanged================="+mGroupDemo.getWidth()+"     "+mGroupDemo.getHeight());
            System.out.println("=============onWindowFocusChanged================="+mGroupDemo.getMeasuredWidth()+"     "+mGroupDemo.getMeasuredHeight());
        }
    }
 ViewTreeObserver observer = mGroupDemo.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //一定要remove
                mGroupDemo.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                System.out.println("=============onGlobalLayout================="+mGroupDemo.getWidth()+"     "+mGroupDemo.getHeight());
                System.out.println("=============onGlobalLayout================="+mGroupDemo.getMeasuredWidth()+"     "+mGroupDemo.getMeasuredHeight());
            }
        });

结果:
=onGlobalLayout=720 200
=onGlobalLayout
=720 200
=onWindowFocusChanged=720 200
=onWindowFocusChanged
=720 200

2 说明getMeasuredHeight和getHeight的值的区别

通过上面的结果可以发现,getMeasuredHeight和getHeight的值是相同的,getMeasureWidth和getWidth的值是相同的,那么这两个值到底有什么区别呢?下面只讨论高度问题。
首先可以得出的结论是LinearLayout内部的内容超过了LinearLayout的高度,所以没有显示全内部内容,所以getMeasuredHeight和getHeight的值和内部关系不大(有关系也是需要我们去添加)。

public class LinearLayoutDemo extends LinearLayout {
    public LinearLayoutDemo(Context context) {
        this(context,null);
    }

    public LinearLayoutDemo(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public LinearLayoutDemo(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       int childCount = getChildCount();
        int actHeight = 0;
        for (int i=0;i< childCount;i++){
            View view = getChildAt(i);
            MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
            measureChild(view,widthMeasureSpec,heightMeasureSpec);
            actHeight += view.getMeasuredHeight() + 50;
        }

        setMeasuredDimension(700,actHeight);

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        View view = getChildAt(0);
        view.layout(l,0,r,100);
        System.out.println("===========onLayout==============="+getMeasuredHeight());
        System.out.println("===========onLayout==============="+getHeight());
    }

}

布局文件

        <com.ldx.canvasdrawdemo.LinearLayoutDemo
            android:id="@+id/view_group_demo"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:orientation="vertical">
            <TextView
                android:id="@+id/demo_tv1"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:text="sjldjflsjfljs"/>
        </com.ldx.canvasdrawdemo.LinearLayoutDemo>
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main15);
        mGroupDemo = findViewById(R.id.view_group_demo);
        textView1 = findViewById(R.id.demo_tv1);

        ViewTreeObserver observer = mGroupDemo.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //一定要remove
                mGroupDemo.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                System.out.println("=============onGlobalLayout================="+textView1.getWidth()+"     "+textView1.getHeight());
                System.out.println("=============onGlobalLayout================="+textView1.getMeasuredWidth()+"     "+textView1.getMeasuredHeight());
            }
        });

    }

结果:
=onGlobalLayout=720 100
=onGlobalLayout
=720 100

修改:

 @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        View view = getChildAt(0);
        view.layout(l,0,r,150);
        System.out.println("===========onLayout==============="+getMeasuredHeight());
        System.out.println("===========onLayout==============="+getHeight());
    }

结果:
=onGlobalLayout=720 150
=onGlobalLayout
=720 100
说明:

  • getMeasuredHeight,getMeasureWidth在view测量后确定( setMeasuredDimension()后),所以又被称为测量宽高,它们只有在measure函数执行后才会有值(或者主动调用measure,measureChild),在layout方法中会用到。
  • getHeight,getWidth在layout函数执行之后有值,会在draw方法中使用。
  • onLayout方法中可以使用getMeasuredWidth方法,如果要在onMeasure中使用getMeasuredHeight方法,只需要调用view的measure或者measureChild方法,之后就可以调用方法获取。
  • 一般情况下,getHeight和getMeasureHeight得到的值是一致的,但是layout如果不按照measure测量得到的值进行设置,也可能两者不相同。
  • getMeasureHeight是自己测量得到的值,告诉父布局我想要多少值,父布局分配宽高时会参考这个值,但具体分配多少由父布局定;getHeight是父布局告诉我值为多少值就是多少,都不是View的真实高度。

getMeasureHeight的值会根据布局文件中的模式和指定的高度进行确定,也可以直接复写onMeasure指定高度。调用 setMeasuredDimension(700,100);就可以完成对高度的指定,布局文件中的模式和高度值也就没有意义了。

源码分析

getMeasureHeight,最终和setMeasuredDimension设置的值有关

    /*
     * @return The raw measured height of this view.
     * getMeasuredHeight,利用了mMeasuredHeight & MEASURED_SIZE_MASK两个值
     */
    public final int getMeasuredHeight() {
        return mMeasuredHeight & MEASURED_SIZE_MASK;
    }

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

    protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        boolean optical = isLayoutModeOptical(this);
        if (optical != isLayoutModeOptical(mParent)) {
            Insets insets = getOpticalInsets();
            int opticalWidth  = insets.left + insets.right;
            int opticalHeight = insets.top  + insets.bottom;

            measuredWidth  += optical ? opticalWidth  : -opticalWidth;
            measuredHeight += optical ? opticalHeight : -opticalHeight;
        }
        setMeasuredDimensionRaw(measuredWidth, measuredHeight);
    }

    private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
        mMeasuredWidth = measuredWidth;
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }

getHeight和父布局有关:

 public final int getHeight() {
        return mBottom - mTop;
    }
/**
     * Assign a size and position to a view and all of its
     * descendants
     *
     * <p>This is the second phase of the layout mechanism.
     * (The first is measuring). In this phase, each parent calls
     * layout on all of its children to position them.
     * This is typically done using the child measurements
     * that were stored in the measure pass().</p>
     *
     * <p>Derived classes should not override this method.
     * Derived classes with children should override
     * onLayout. In that method, they should
     * call layout on each of their children.</p>
     * //仔细看四个参数的解释,都是相对父布局的,所以getHeight,getWidth都跟父布局有关系(默认情况下)。
     * @param l Left position, relative to parent
     * @param t Top position, relative to parent
     * @param r Right position, relative to parent
     * @param b Bottom position, relative to parent
     */
    @SuppressWarnings({"unchecked"})
    public void layout(int l, int t, int r, int b) {
        if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
            onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
            mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        }

        int oldL = mLeft;
        int oldT = mTop;
        int oldB = mBottom;
        int oldR = mRight;

		//关键代码
        boolean changed = isLayoutModeOptical(mParent) ?
                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);

        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
            onLayout(changed, l, t, r, b);
   。。。。。。。。。。。
      
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值