自定義組件之淺談onMeasure

一潮太、默認處理

View類默認實現(xiàn):

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

默認實現(xiàn)中丛晦,調(diào)用了setMeasuredDimension( )設(shè)置測量后的寬高,這個方法需要兩個參數(shù),也就是我們測量后的寬左驾、高信息.

二镣隶、widthMeasureSpec、heightMeasureSpec

1诡右、寬安岂、高信息

不管是重寫onMeasure還是默認的實現(xiàn)中,我們都可以看到兩個int類型值:widthMeasureSpec帆吻、heightMeasureSpec.

這兩個int類型值就是寬和高信息域那,注意:無論寬度信息(widthMeasureSpec)還是高度信息(widthMeasureSpec),都包含兩種數(shù)據(jù)------模式猜煮、大小次员,模式是根據(jù)wrap_content、match_parent王带、具體值來確定的淑蔚,大小則是根據(jù)不同模式進行計算.

2、模式

我們在xml中定義layout_width愕撰、layout_height屬性時有3種情況:

wrap_content
match_parent
具體值

寬刹衫、高信息中的模式也有三個不同的常量值:

MeasureSpec.EXACTLY
當(dāng)組件的尺寸為match_parent或具體值時用該常量值表示此時的模式

MeasureSpec.AT_MOST
當(dāng)組件的尺寸為wrap_content時用該常量值表示此時的模式

MeasureSpec.UNSPECIFIED
未指定尺寸醋寝,一般用不到

很好理解,EXACTLY譯為確定的带迟,使用match_parent表示組件大小匹配父容器音羞,而父容器本身也是一個組件,它會計算出自己的大小仓犬,我們不需要重復(fù)去計算嗅绰,所以無論是match_parent還是具體值,組件大小都是確定的婶肩,所以這兩種情況都用MeasureSpec.EXACTLY來表示.

使用wrap_content(包裹內(nèi)容)時办陷,此時組件的大小需要根據(jù)內(nèi)容確定,只要在父容器指定的最大尺寸之內(nèi)就行了律歼,用MeasureSpec.AT_MOST來表示.

MeasureSpec.UNSPECIFIED表示父容器對子視圖不進行任何約束民镜,子視圖可以是它想要的任何大小,一般用不到.

3险毁、獲取模式制圈、大小

widthMeasureSpec、heightMeasureSpec都是一個int類型值畔况,那么一個int
怎么保存模式鲸鹦、大小這兩種數(shù)據(jù)呢?

我們都知道:int類型占用4個字節(jié)跷跪,一共32位. 而widthMeasureSpec和heightMeasureSpec的前2位代表模式馋嗜,后30位表示大小.

ok,既然知道怎么表示的吵瞻,那么我們可以通過位運算來獲取模式和大懈鸸健:

模式  int mode = widthMeasureSpec & 0x3 << 30;
大小  int size = widthMeasureSpec & ~0x3 << 30;

每次都要進行位運算很麻煩,所以系統(tǒng)提供了MeasureSpec類橡羞,這個類有3個常量(就是上面的三種模式)以及一些靜態(tài)方法:

三種模式:
          MeasureSpec.EXACTLY
          MeasureSpec.AT_MOST
          MeasureSpec.UNSPECIFIED

方法:
        public static int makeMeasureSpec(int size, int mode) 
        傳入尺寸大小和模式生成一個包含這兩個信息的int類型值

        從一個包含模式眯停、大小的int類型值中獲取模式、大小
        public static int getMode(int measureSpec)
        public static int getSize(int measureSpec)

三卿泽、正方形View

public class XView extends View {

    public XView(Context context) {
        this(context, null);
    }

    public XView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public XView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = myMeasure(0, widthMeasureSpec);
        int height = myMeasure(0, heightMeasureSpec);

        // 和系統(tǒng)onMeasure() 方法不同的是:我添加了下面的if-else語句
        if (width > height) {
            width = height;
        } else {
            height = width;
        }

        setMeasuredDimension(width, height);
    }

    /**
     *雖然寫著方法名是myMeasure莺债,但是其實這就是View類getDefaultSize()方法的源碼
     *注意看文章開頭,setMeasuredDimension()需要的兩個參數(shù):寬签夭、高信息都是通過這個方法生成的
     */
    private int myMeasure(int defaultValue, int measureSpec) {
        int result = defaultValue;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
            case MeasureSpec.UNSPECIFIED:
                result = defaultValue;
                break;
            case MeasureSpec.AT_MOST:
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
        }
        return result;
    }

}

上面定義了一個正方形的XView齐邦,不論XView在布局文件中的寬、高如何定義第租,顯示在界面上始終是一個正方形的View(你需要設(shè)置一個背景顏色侄旬,不然看不出效果),感興趣的可以運行查看效果.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末煌妈,一起剝皮案震驚了整個濱河市儡羔,隨后出現(xiàn)的幾起案子宣羊,更是在濱河造成了極大的恐慌,老刑警劉巖汰蜘,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仇冯,死亡現(xiàn)場離奇詭異,居然都是意外死亡族操,警方通過查閱死者的電腦和手機苛坚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來色难,“玉大人泼舱,你說我怎么就攤上這事〖侠颍” “怎么了娇昙?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長笤妙。 經(jīng)常有香客問我冒掌,道長,這世上最難降的妖魔是什么蹲盘? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任股毫,我火速辦了婚禮,結(jié)果婚禮上召衔,老公的妹妹穿的比我還像新娘铃诬。我一直安慰自己,他們只是感情好苍凛,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布趣席。 她就那樣靜靜地躺著,像睡著了一般毫深。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毒姨,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天哑蔫,我揣著相機與錄音,去河邊找鬼弧呐。 笑死闸迷,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的俘枫。 我是一名探鬼主播腥沽,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鸠蚪!你這毒婦竟也來了今阳?” 一聲冷哼從身側(cè)響起师溅,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盾舌,沒想到半個月后墓臭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡妖谴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年窿锉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膝舅。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡嗡载,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仍稀,到底是詐尸還是另有隱情洼滚,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布琳轿,位于F島的核電站判沟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏崭篡。R本人自食惡果不足惜挪哄,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琉闪。 院中可真熱鬧迹炼,春花似錦、人聲如沸颠毙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛀蜜。三九已至刻两,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滴某,已是汗流浹背磅摹。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留霎奢,地道東北人户誓。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像幕侠,于是被迫代替她去往敵國和親帝美。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359