android MeasureSpec的三個測量模式


1.MeasureSpec含義

其實可以去看MeasureSpec的文檔,里面對MeasureSpec的作用介紹得很清楚.MeasureSpec封裝了父布局傳遞給子布局的布局要求,每個MeasureSpec代表了一組寬度和高度的要求。

2.MeasureSpec的三個模式詳解不定的,恰恰和AT_MOST

視圖大小的基本定義如下:
MeasureSpec.EXACTLY - 視圖應該是這么多像素,無論它實際上有多大。
MeasureSpec.AT_MOST - 如果視圖的尺寸較小,則視圖可以是此尺寸或更小。
MeasureSpec.UNSPECIFIED - 視圖可以是它需要的任何大小,以顯示它需要顯示的內容。
如果父視圖的大小綁定,MeasureSpec.AT_MOST將應用於已設置為WRAP_CONTENT的視圖。例如,您的父視圖可能綁定到屏幕大小。它的孩子也會受到這種規模的束縛,但它可能不會那么大。因此,父視圖將MeasureSpec設置為AT_MOST,告訴孩子它可以是0到屏幕大小之間的任何位置。孩子必須做出調整,以確保它符合所提供的范圍。
在特殊情況下,界限無關緊要。例如,ScrollView。對於ScrollView,子視圖的高度無關緊要。因此,它將為孩子們提供一個未知的視圖,告訴孩子他們可以達到他們需要的高度。ScrollView將處理它們的繪圖和放置。

翻譯一下(直接用軟件翻譯過來的,不明白的話,下面會通過例子說明):

查看的大小基本定義如下:
MeasureSpec.EXACTLY - 表示父控件已經確切的指定了子查看的大小.MeasureSpec.AT_MOST
- 表示子查看具體大小沒有尺寸限制,但是存在上限,上限一般為父查看大小.MeasureSpec
。未知 - 父控件沒有給子視任何限制,子查看可以設置為任意大小。
如果父視圖的大小已經指定則MeasureSpec.AT_MOST將應用於已設置為WRAP_CONTENT的子視圖。例如,你的父視圖可能綁定到屏幕大小。它的孩子也會綁定到這個大小,但它可能不是那么大。因此,父視圖將MeasureSpec設置為AT_MOST,它告訴孩子它可以在0和屏幕之間的任何地方。孩子必須進行調整,以確保它符合提供的界限。
在特殊情況下,界限無關緊要。例如,一個ScrollView。在ScrollView的情況下,子視圖的高度是不相關的。因此,它將向孩子提供一個未知視圖,告訴孩子他們可以像他們需要的一樣高 .ScrollView將處理它們的繪圖和放置。

模式 數值 描述
UNSPECIFIED 0(0x00000000) 父控件沒有給子視圖任何限制,子視圖可以設置為任意大小。
究竟 1073741824(0x40000000) 表示父控件已經確切的指定了子視圖的大小。
最多 -2147483648(0x80000000) 表示子查看具體大小沒有尺寸限制,但是存在上限,上限一般為父視圖大小。

3.例子解析

這里分為兩個部分例子,例子一是父布局是LinearLayout中,子布局是LinearLayout中,例子二是是父布局是滾動型,子布局是LinearLayout中。

1)例子一解釋EXACTLY和AT_MOST

布局文件

<?xml version="1.0" encoding="utf-8"?> <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" > <com.example.transdotnavi.widget.NormalDot android:id="@+id/dot1" android:layout_width="20dp" android:layout_height="match_parent" android:background="#F7F6F5" > </com.example.transdotnavi.widget.NormalDot> </LinearLayout> 

子控件,對於具體解釋可以看下面代碼里的注釋

/** * @author Administrator * 2016-10-22 * * 普通的圓點導航器 * 用於測試父控件是layout,子控件是layout的情況 * 具體可以看layout.xml,里面定義了一個LinearLayout父布局,和一個NormalDot子布局 * 測試機器:160dpi 480*800 */ public class NormalDot extends LinearLayout { public NormalDot(Context context) { super(context); } @SuppressLint("NewApi") public NormalDot(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public NormalDot(Context context, AttributeSet attrs) { super(context, attrs); } // MeasureSpec.AT_MOST = -2147483648 [0x80000000]; // MeasureSpec.EXACTLY = 1073741824 [0x40000000]; // MeasureSpec.UNSPECIFIED = 0 [0x0]; // 父布局LinearLayout固定width,height是match_parent(其實如果設置為wrap_content它的寬高也是等於屏幕寬高) // 情況一: // 當寬或高設為確定值時:即width=20dp,height=30dp,或者為match_parent。它會使用MeasureSpec.EXACTLY測量模式(表示父控件已經確切的指定了子View的大小) // 情況二: // 當寬或高設為wrap_content時,它會使用MeasureSpec.AT_MOST測量模式(表示子View具體大小沒有尺寸限制,但是存在上限,上限一般為父View大小) // 情況三: // MeasureSpec.UNSPECIFIED,一般是在特殊情況下出現,如在父布局是ScrollView中才會出現這種測量模式 // 注意: // 父視圖可能綁定到屏幕大小。 它的孩子也會綁定到這個大小,但它可能不是那么大。 // 因此,父視圖將MeasureSpec設置為AT_MOST , // 它告訴孩子它可以在0和屏幕之間的任何地方。 孩子必須進行調整,以確保它符合提供的界限。 // 通過一個例子解釋上面面這句化的意思 // 父布局寬高都設置為match_parent,這時候父布局大小就是屏幕大小,這時候,他的子視圖設置為width=20dp,height=wrap_content // 看打出了的日志可以看到寬是20,高是800,這樣的話我們應該能在屏幕的左邊看到一條白色的寬為20的豎線, // 但是事實上,我們在界面是沒有看到這條豎線的,這是因為子布局可以占據0到屏幕大小這個范圍,但是子布局通過調整,將height設置為0了,所以 // 我們看不到任何圖像 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mode = MeasureSpec.getMode(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int mode2 = MeasureSpec.getMode(heightMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); Log.i("lgy", "mode:"+mode+" width:"+width); Log.i("lgy", "mode2:"+mode2+" height:"+height); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } 

2)例子二解析的評論模式

布局文件

<?xml version="1.0" encoding="utf-8"?> <com.example.transdotnavi.widget.LScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.transdotnavi.widget.NormalDot2 android:id="@+id/dot2" android:layout_width="50dp" android:layout_height="50dp" android:background="#F7F6F5" > <!-- <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> --> </com.example.transdotnavi.widget.NormalDot2> </com.example.transdotnavi.widget.LScrollView> 

子控件

/** * @author Administrator * 2016-10-22 * * 普通的圓點導航器 * 用於測試父控件是ScrollView,子控件是layout的情況 * 具體可以看layout2.xml,里面定義了一個ScrollView父布局,和一個NormalDot2子布局 * 測試機器:160dpi 480*800 */ public class NormalDot2 extends LinearLayout { public NormalDot2(Context context) { super(context); } /** * @param context * @param attrs * @param defStyleAttr */ @SuppressLint("NewApi") public NormalDot2(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub } /** * @param context * @param attrs */ public NormalDot2(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } // MeasureSpec.AT_MOST = -2147483648 [0x80000000]; // MeasureSpec.EXACTLY = 1073741824 [0x40000000]; // MeasureSpec.UNSPECIFIED = 0 [0x0]; // 這里主要展示的是MeasureSpec.UNSPECIFIED測量模式 // 情況一:垂直的ScrollView // 父布局ScrollView寬高都是match_parent,子布局是一個NormalDot2設置寬高都是50dp // 從打出的日志可以看到,寬是以MeasureSpec.EXACTLY模式測量的,width=50, // 而高是以MeasureSpec.UNSPECIFIED模式測量的,height=0 // 這時候如果NormalDot2布局里沒有任何控件,那么就不會顯示任何東西 // 但如果在里面加個TextView,那么這個textView就會顯示出來(當然這個textView是有內容的,否則也不會顯示出來), // 但這時候height還是以MeasureSpec.UNSPECIFIED模式測量,height=0 // 情況二:水平的ScrollView // 父布局HorizontalScrollView寬高都是match_parent,子布局是一個NormalDot2設置寬高都是50dp // 從打出的日志可以看到,寬是MeasureSpec.UNSPECIFIED模式測量的,width=0, // 而高是以MeasureSpec.EXACTLY模式測量的,height=50 // 這時候如果NormalDot2布局里沒有任何控件,那么就不會顯示任何東西 // 但如果在里面加個TextView,那么這個textView就會顯示出來(當然這個textView是有內容的,否則也不會顯示出來), // 但這時候width還是以MeasureSpec.UNSPECIFIED模式測量,width=0 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mode = MeasureSpec.getMode(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int mode2 = MeasureSpec.getMode(heightMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); Log.i("lgy", "============mode:"+mode+" width:"+width); Log.i("lgy", "=============mode2:"+mode2+" height:"+height); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } 

父控件(滾動型)

/** * @author LGY * @time 2016-10-23 * @action */ public class LScrollView extends HorizontalScrollView //ScrollView { /** * @param context */ public LScrollView(Context context) { super(context); // TODO Auto-generated constructor stub } /** * @param context * @param attrs * @param defStyleAttr */ public LScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub } /** * @param context * @param attrs */ public LScrollView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } /* (non-Javadoc) * @see android.widget.ScrollView#onMeasure(int, int) */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mode = MeasureSpec.getMode(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int mode2 = MeasureSpec.getMode(heightMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); Log.i("lgy", "ScrollViewmode:"+mode+" width:"+width); Log.i("lgy", "ScrollViewmode2:"+mode2+" height:"+height); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM