移動開發 怎樣自己定義ViewGroup

2021-09-07 06:18:58 字數 4214 閱讀 3185

本文翻譯自《50 android hacks》

按照慣例。先從乙個樣例說起。

非常easy,3張撲克牌疊在一起顯示。

這個布局效果該怎樣實現呢?有的同學該說了,這非常easy啊,用relativelayout或framelayout,然後為每乙個撲克牌設定margin就能實現了。

ok,那就看一下通過這樣的方式是怎樣實現的。

**例如以下:

效果圖

沒錯,通過這樣的方式是能夠實現的。

可是。不認為這樣的方式有點low嗎?!

讓我們用高階一點的方式去實現它,提公升一下自己的逼格!

定製viewgroup之前,我們須要先理解幾個概念。

android繪製檢視的方式

這裡我不會涉及太多的細節,可是須要理解android開發文件中的一段話:

「繪製布局由兩個遍歷過程組成:測量過程和布局過程。

測量過程由measure(int, int)方法完畢,該方法從上到下遍歷檢視樹。

在遞迴遍歷過程中。每乙個檢視都會向下層傳遞尺寸和規格。當measure方法遍歷結束,每乙個檢視都儲存了各自的尺寸資訊。第二個過程由layout(int,int,int,int)方法完畢,該方法也是由上而下遍歷檢視樹。在遍歷過程中,每乙個父檢視通過測量過程的結果定位全部子檢視的位置資訊。

簡而言之,第一步是測量viewgroup的寬度和高度,在onmeasure()方法中完畢,viewgroup遍歷全部子檢視計算出它的大小。第二步是依據第一步獲取的尺寸去布局全部子檢視,在onlayout()中完畢。

建立cascadelayout

最終到了定製viewgroup的階段了。

假設我們已經定製了乙個cascadelayout的容器。我們會這樣使用它。

首先,定義屬性。在values目錄以下建立attrs.xml。**例如以下:

同一時候,為了嚴謹一些,定義一些預設的垂直距離和水平距離,以防在布局中沒有提供這些屬性。

在dimens.xml中加入例如以下**:

10dp

10dp

準備工作已經做好了。接下來看一下cascadelayout的源**,稍微有點長,後面幫助大家分析一下。

public class cascadelayout extends viewgroup  finally 

} @override

protected void onmeasure(int widthmeasurespec, int heightmeasurespec)

width += child.getmeasuredwidth();

height += verticalspacing;

}width += getpaddingright();

height += getchildat(getchildcount() - 1).getmeasuredheight()

+ getpaddingbottom();

setmeasureddimension(resolvesize(width, widthmeasurespec),

resolvesize(height, heightmeasurespec));

} @override

protected void onlayout(boolean changed, int l, int t, int r, int b)

} @override

protected boolean checklayoutparams(viewgroup.layoutparams p)

@override

protected layoutparams generatedefaultlayoutparams()

@override

public layoutparams generatelayoutparams(attributeset attrs)

@override

protected layoutparams generatelayoutparams(viewgroup.layoutparams p)

public static class layoutparams extends viewgroup.layoutparams

public layoutparams(int w, int h)

}}

首先,分析建構函式。

public cascadelayout(context context, attributeset attrs)  finally 

}

假設在布局中使用casecadelayout,系統就會呼叫這個建構函式,這個大家都應該知道的吧。這裡不解釋why。有興趣的能夠去看源**,重點看系統是怎樣解析xml布局的。

建構函式非常easy,就是通過布局檔案裡的屬性,獲取水平距離和垂直距離。

然後。分析自己定義layoutparams。

public static class layoutparams extends viewgroup.layoutparams 

public layoutparams(int w, int h)

}

除此之外。還須要重寫一些方法。checklayoutparams()、generatedefaultlayoutparams()等,這種方法在不同viewgroup之間往往是同樣的。

接下來。分析onmeasure()方法。

@override

protected void onmeasure(int widthmeasurespec, int heightmeasurespec)

width += child.getmeasuredwidth();

height += verticalspacing;

}width += getpaddingright();

height += getchildat(getchildcount() - 1).getmeasuredheight()

+ getpaddingbottom();

// 使用計算所得的寬和高設定整個布局的測量尺寸

setmeasureddimension(resolvesize(width, widthmeasurespec),

resolvesize(height, heightmeasurespec));

}

最後,分析onlayout()方法。

@override

protected void onlayout(boolean changed, int l, int t, int r, int b)

}

邏輯非常easy。用onmeasure()方法計算出的值為引數迴圈呼叫子view的layout()方法。

為子檢視加入自己定義屬性

作為演示樣例。以下將加入子檢視重寫垂直間距的方法。

第一步是向attrs.xml中加入乙個新的屬性。

這裡的屬性名是layout_vertical_spacing,由於該屬性名字首是layout_。同一時候,又不是view固有的屬性。所以該屬性會被加入到layoutparams的屬性表中。在cascadelayout類的建構函式中讀取這個新屬性。

public static class layoutparams extends viewgroup.layoutparams  finally 

}public layoutparams(int w, int h)

}

那怎麼使用這個屬性呢?so easy!

參考資料

怎樣給filter加入自己定義介面

給乙個filter加入介面,過程例如以下 1 建立乙個宣告介面的標頭檔案 inte ce.h 內容包含指定介面的guid 使用guidgen.exe 以及介面函式的宣告。記得加 initguid.h 的include,不然使用時會出現 無法解析的外部符號 iid 錯誤 2 在cfilter類的標頭檔...

iOS中怎樣加入自己定義的字型

蘋果對於開發,確實在細節方面下了非常大的功夫,只是不管乙個平台下多大的功夫,仍然會有些需求是無法涵蓋的。比方字型吧。我們的應用為了能更加個性化。會須要不同的字型。有時候有些字型是非常特殊的。甚至是購買的。那麼這些字型怎樣加到專案中去呢?在準備好了字型檔檔案後,就能夠加到專案中了,是把ttf檔案增加到...

移動開發 如何自定義ViewGroup

本文翻譯自 50 android hacks 依照慣例,先從乙個例子說起。很簡單,3張撲克牌疊在一起顯示。這個布局效果該如何實現呢?有的同學該說了,這很簡單啊,用relativelayout或framelayout,然後為每乙個撲克牌設定margin就能實現了。ok,那就看一下通過這種方式是如何實現...