Android View 如何測量

  對於Android View的測量,咱們一句話總結爲:"給我位置和大小,我就知道您長到那裏"。android

  爲了讓你們更好的理解這個結論,我這裏先講一個平常生活中的小故事:不知道你們玩過"瞎子畫畫"的遊戲沒,一我的蒙上眼睛,拿筆去畫板上畫一些指定的圖案,另一我的則充當他的"眼睛",經過語言告訴他在畫板那個位置畫一個多大的圖案。假若,這我的不告訴那個蒙着眼睛的人,在那個畫一個多大的圖案。那麼這個蒙着眼睛的人此時真是"河裏趕大車----------沒轍"。其實,Android就是這個蒙着眼睛的人,咱們必須精確地告訴他如何去畫,它才能畫出你所想要的圖形。ide

  你們是否是對Android佈局的測量進行現實世界進行類比了。爲了實現View具體佈局在哪兒,Android設計了一個短小精悍又功能強大的類——measureSpec類。這樣媽媽不再用擔憂我不會測量View了。那麼,MeasureSpec究竟是個什麼鬼了。MeasureSpec,歸根結底是一個32位的int值。其中高2位表示測量的模式,低30位表示測量View的大小。這樣作有什麼好處。這樣作經過位運算來提升運行效率。佈局

  要了解MeasureSpec這個類的來弄去脈的話,務必要對測量的三種模式瞭解。設計

  1.EXACTLY(精準的)xml

  當您設置View的layout_height屬性或layout_width屬性爲肯定的值或者爲match_parent(填充父容器)時候,系統就將View測量模式設置爲EXACTLY模式。blog

  2.AT_MOST(最大值)遊戲

  即佈局爲最大值模式,那麼何時系統會將View調整爲AT_MOST模式了,即當您設置View的layout_height屬性或layout_width屬性爲wrap_content(包裹內容)時候。get

  3.UNSPECIFIED(未肯定)it

  即沒有肯定,沒有指定大小測量模式,view即「心有多大,舞臺就有多大"。這個方法,通常在自定義控件中才能用到。io

  View測量的時候,默認是EXACTLY模式,也許你會感到納悶,TextView,EditText這些控件,他怎麼就支持wrap_content屬性了,難道他重寫OnMeasure方法,是的,他們都重寫OnMeasure方法。這就是爲何咱們在自定義控件的時候,若是要佈局支持wrap_content屬性,就須要重寫onMeasure方法,來指定wrap_content爲確切的大小。

  這個關於測量模式的思惟導圖應該是這樣的:

  

  咱們知道這麼多理論的知識,是否是以爲即枯燥乏味又以爲然並卵。好吧,咱們就直接上代碼,在代碼中解釋MeasureSpec如何獲取測量模式和測量的大小。源代碼以下:

   Java代碼以下:

public class MyView extends View {
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
}

  xml代碼以下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >
        
        <com.example.test.MyView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#00ff00"
            />
</LinearLayout>

  運行效果以下所示:

  經過這個短小精悍的例子,充分證實這樣一個結論:View測量的時候,默認是EXACTLY模式,你不重寫OnMeasure方法,即便設置wrap_content屬性,他也是填充父容器。

  那麼,就經過MeasureSpec這個萬金油類來重寫一下OnMeasure方法。相應源代碼以下:

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec),
                measureWidth(heightMeasureSpec));
    }
    public int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = 200;
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(specSize, result);
            }
        }
        return result;
    }

  運行效果以下:

  一樣的例子,咱們只不過是重寫了OnMeasure方法,經過MeasureSpec.getMode(measureSpec)獲取測量模式的時候,經過MeasureSpec.getSize(measureSpec)獲取控件尺寸。判斷當佈局屬性爲wrap_content,指定爲一確切值,這時,控件就符合wrap_content屬性。

  本文對Android如何對控件進行測量介紹,本人才疏學淺,懇請你們指教。

相關文章
相關標籤/搜索