先给出一个结论:getMeasuredWidth()获取的是view原始的大小,也就是这个view在XML文件中配置或者是代码中设置的大小。getWidth()获取的是这个view最终显示的大小,这个大小有可能等于原始的大小也有可能不等于原始大小。

从源码上开始分析一下这两个方法的区别。首先来看一下getMeasuredWidth()这个方法。

  1. public final int getMeasuredWidth() {
  2. return mMeasuredWidth & MEASURED_SIZE_MASK;
  3. }
  4.  
  5. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  6. setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
  7. getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
  8. }
  9.  
  10. protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
  11. boolean optical = isLayoutModeOptical(this);
  12. if (optical != isLayoutModeOptical(mParent)) {
  13. Insets insets = getOpticalInsets();
  14. int opticalWidth = insets.left + insets.right;
  15. int opticalHeight = insets.top + insets.bottom;
  16.  
  17. measuredWidth += optical ? opticalWidth : -opticalWidth;
  18. measuredHeight += optical ? opticalHeight : -opticalHeight;
  19. }
  20. setMeasuredDimensionRaw(measuredWidth, measuredHeight);
  21. }
  22.  
  23. private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
  24. mMeasuredWidth = measuredWidth;
  25. 25 mMeasuredHeight = measuredHeight;
  26.  
  27. mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
  28. }

从源码上来看,getMeasuredWidth()获取的是mMeasuredWidth的这个值。这个值是一个8位的十六进制的数字,高两位表示的是这个measure阶段的Mode的值,具体可以查看MeasureSpec的原理。这里mMeasuredWidth & MEASURED_SIZE_MASK表示的是测量阶段结束之后,view真实的值。而且这个值会在调用了setMeasuredDimensionRaw()函数之后会被设置。所以getMeasuredWidth()的值是measure阶段结束之后得到的view的原始的值。

再来看看getWidth()的源码:

  1. public final int getWidth() {
  2. return mRight - mLeft;
  3. }

那么问题来了,mRight和mLeft是什么值,是在什么时候被设置的。我们再看layout阶段的源码:

  1. public void layout(int l, int t, int r, int b) {
  2. if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
  3. onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
  4. mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
  5. }
  6.  
  7. int oldL = mLeft;
  8. int oldT = mTop;
  9. int oldB = mBottom;
  10. int oldR = mRight;
  11.  
  12. boolean changed = isLayoutModeOptical(mParent) ?
  13. setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
  14.  
  15. ...
  16. }

在layout阶段会去调用setOpticalFrame()或者调用setFrame()方法,从源码中可知setOpticalFrame()方法,最终还是调用的setFrame()方法。

  1. protected boolean setFrame(int left, int top, int right, int bottom) {
  2. boolean changed = false;
  3.  
  4. if (DBG) {
  5. Log.d("View", this + " View.setFrame(" + left + "," + top + ","
  6. + right + "," + bottom + ")");
  7. }
  8.  
  9. if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
  10. changed = true;
  11.  
  12. // Remember our drawn bit
  13. int drawn = mPrivateFlags & PFLAG_DRAWN;
  14.  
  15. int oldWidth = mRight - mLeft;
  16. int oldHeight = mBottom - mTop;
  17. int newWidth = right - left;
  18. int newHeight = bottom - top;
  19. boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
  20.  
  21. // Invalidate our old position
  22. invalidate(sizeChanged);
  23.  
  24. mLeft = left;
  25. mTop = top;
  26. mRight = right;
  27. mBottom = bottom;
  28. mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
  29.  
  30. mPrivateFlags |= PFLAG_HAS_BOUNDS;
  31. ...
  32. }

所以最终的mLeft和mRight的值是在setFrame()方法中被设置的。而且这些mLeft,mRight代表了view最终显示在界面中的大小。

下面我们自定义一个简单的ViewGroup,在layout阶段改变left,right的值,观察getMeasuredWidth()和getWidth()方法之间的区别。

  1. package com.gearmotion.app.customviewgroup;
  2.  
  3. import android.content.Context;
  4. import android.util.AttributeSet;
  5. import android.view.View;
  6. import android.widget.RelativeLayout;
  7.  
  8. /**
  9. * Created by Charles on 2015/11/21.
  10. */
  11. public class CustomViewGroup extends RelativeLayout {
  12.  
  13. public CustomViewGroup(Context context) {
  14. super(context);
  15. }
  16.  
  17. public CustomViewGroup(Context context, AttributeSet attrs) {
  18. super(context, attrs);
  19. }
  20.  
  21. public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
  22. super(context, attrs, defStyleAttr);
  23. }
  24.  
  25. @Override
  26. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  27. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  28. }
  29.  
  30. @Override
  31. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  32. super.onLayout(changed, l, t, r, b);
  33. View child = this.getChildAt(1); //the textview
  34. //add 100px for right
  35. child.layout(child.getLeft(), child.getTop(),child.getRight() + 100,child.getBottom());
  36.  
  37. }
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <com.gearmotion.app.customviewgroup.CustomViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. tools:context="com.gearmotion.app.customviewgroup.MainActivity">
  7.  
  8. <LinearLayout
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:orientation="horizontal">
  12.  
  13. <Button
  14. android:id="@+id/left"
  15. android:layout_width="0dp"
  16. android:layout_height="wrap_content"
  17. android:layout_weight="1"
  18. android:gravity="center"
  19. android:text="width" />
  20.  
  21. <Button
  22. android:id="@+id/right"
  23. android:layout_width="0dp"
  24. android:layout_height="wrap_content"
  25. android:layout_weight="1"
  26. android:gravity="center"
  27. android:text="measuredWidth" />
  28. </LinearLayout>
  29.  
  30. <TextView
  31. android:id="@+id/textview"
  32. android:layout_width="100px"
  33. android:layout_height="wrap_content"
  34. android:layout_centerInParent="true"
  35. android:background="#8EE5EE"
  36. android:gravity="center"
  37. android:text="textview" />
  38.  
  39. </com.gearmotion.app.customviewgroup.CustomViewGroup>
  1. package com.gearmotion.app.customviewgroup;
  2.  
  3. import android.support.v7.app.AppCompatActivity;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.widget.Button;
  7. import android.widget.TextView;
  8. import android.widget.Toast;
  9.  
  10. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  11.  
  12. TextView mTextView;
  13. Button mLeftBtn;
  14. Button mRightBtn;
  15.  
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_main);
  20.  
  21. mTextView = (TextView) this.findViewById(R.id.textview);
  22. mLeftBtn = (Button) this.findViewById(R.id.left);
  23. mRightBtn = (Button) this.findViewById(R.id.right);
  24. mLeftBtn.setOnClickListener(this);
  25. mRightBtn.setOnClickListener(this);
  26. }
  27.  
  28. @Override
  29. public void onClick(View v) {
  30. int id = v.getId();
  31. switch (id) {
  32. case R.id.left: //width
  33. Toast.makeText(MainActivity.this, "width:" + mTextView.getWidth(), Toast.LENGTH_SHORT).show();
  34. break;
  35. case R.id.right: //measuredWidth
  36. Toast.makeText(MainActivity.this,"measuredWidth:"+mTextView.getMeasuredWidth(),Toast.LENGTH_SHORT).show();
  37. break;
  38. }
  39. }
  40. }

在这个demo中,我们给textview设置宽度为100px,但是在layout阶段给它加大到200,最终结果是:点击width按钮,显示为200,点解measuredWidth按钮显示为100.

android中getWidth()和getMeasuredWidth()之间的区别的更多相关文章

  1. android中getWidth()和getMeasuredWidth()

    getMeasuredWidth()获取的是view原始的大小,也就是这个view在XML文件中配置或者是代码中设置的大小.getWidth()获取的是这个view最终显示的大小,这个大小有可能等于原 ...

  2. JavaScript中this和$(this)之间的区别以及extend的使用

    jQuery中this和$(this)之间的区别: this返回的是当前对象的html对象,而$(this)返回的是当前对象的jQuery对象 举个正确的Demo实例: $("#textbo ...

  3. android中activity.this跟getApplicationContext的区别

    转载: http://www.myexception.cn/android/1968332.html android中activity.this和getApplicationContext的区别 在a ...

  4. [转] C#中out和ref之间的区别

    gskcc 的原文地址 C#中out和ref之间的区别 首先:两者都是按地址传递的,使用后都将改变原来参数的数值. 其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个 ...

  5. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  6. iOS 中 #import同@class之间的区别

    很多刚开始学习iOS开发的同学可能在看别人的代码的时候会发现有部分#import操作写在m文件中,而h文件仅仅使用@class进行声明,不禁纳闷起来,为什么不直接把#import放到h文件中呢? 这是 ...

  7. Android中两个Activity之间简单通信

    在Android中,一个界面被称为一个activity,在两个界面之间通信,采用的是使用一个中间传话者(即Intent类)的模式,而不是直接通信. 下面演示如何实现两个activity之间的通信. 信 ...

  8. Android中sp和px之间关系探究

    记得当时在刚接触Android时都在说不要用px,要用sp,所以在实际工作当中当然就按照这个规则,所以都要将px换算成sp,而我在实际工作中的换算规则是dp=px * 1.5,而且用这种规则到现在基本 ...

  9. angularjs 中 Factory,Service,Provider 之间的区别

    本片文章是使用了 angularjs 中使用 service 在controller 之间 share 对象和数据 的code(http://jsfiddle.net/kn46u0uj/1/) 来进行 ...

随机推荐

  1. 去重函数unique,sort,erase的应用

    std::unique 一.总述 unique函数属于STL中比较常用函数,它的功能是元素去重.即"删除"序列中所有相邻的重复元素(只保留一个).此处的删除,并不 是真的删除,而是 ...

  2. Linux的运行等级与目标

    在老的 Linux 发行版本中,系统运行分成不同的运行级别(run level),不同的级别所启动的服务搭配有所不同.较新的 Linux 发行版本,比如 CentOS 7+,已经将运行级别替换成另一个 ...

  3. .NET CORE 依赖注入 实践总结

    知识点回顾 依赖包. Microsoft.Extensions.DependencyInjection.Abstractions 核心对象和方法. IServiceCollection.注入对象的容器 ...

  4. sql语句中的删除操作

    drop: drop table tb; 删除内容和定义,释放空间.简单来说就是把整个表去掉.以后不能再新增数据,除非新增一个表. truncate: truncate table tb; 删除内容. ...

  5. Android_存储之DataBase之Room

    概述: Room是Google在AndroidX中提供的一个ORM(Object Relational Mapping,对象关系映射)库.它是在SQLite上提供的一个抽象层,可以使用SQLite的全 ...

  6. [Python基础]005.语法(4)

    语法(4) 类 创建 self 方法 变量 综合例子 继承 类 创建 与其他大部分语言一样,Python也用 class 来创建类. class Person: # Person类 pass # 空语 ...

  7. [JavaWeb基础] 004.用JSP + SERVLET 进行简单的增加删除修改

    上一次的文章,我们讲解了如何用JAVA访问MySql数据库,对数据进行增加删除修改查询.那么这次我们把具体的页面的数据库操作结合在一起,进行一次简单的学生信息操作案例. 首先我们创建一个专门用于学生管 ...

  8. 线程池 & 线程调度

    线程池1. 第四种获取线程的方法:线程池,一个 ExecutorService,它使用可能的几个池线程之 一执行每个提交的任务, 通常使用 Executors 工厂方法配置. 2. 线程池可以解决两个 ...

  9. JAVA中的注释方法

    Java的三种注释方法 ①单行注释:使用 // ,其注释内容从//开始到本行结束,比较常用, 快捷键为:Ctrl + / 或者  Ctrl + Shift + C  取消注释:Ctrl + / 或者  ...

  10. 分布式事务解决方案Seata

    Seata全称是Simple Extensible Autonomous Transaction Architecture,是由阿里巴巴开源的具有高性能和易用性的分布式事务解决方案. 微服务中的分布式 ...