在咱們的實際應用中, 常常須要用到自定義控件,好比自定義圓形頭像,自定義計步器等等。但有時咱們不只須要自定義控件,舉個例子,FloatingActionButton 你們都很經常使用,因此你們也很常常會有一種需求,點擊某個 FloatingActionButton 彈出更多 FloatingActionButton ,這個需求的通常思路是寫 n 個 button 而後再一個個的去設置動畫效果。但這實在是太麻煩了,因此網上有個 FloatingActionButtonMenu 這個開源庫,這就是利用到了自定義佈局 「ViewGroup」,如今就讓我給他家介紹下,如何自定義佈局 「layout」。html
相比於自定義 View ,自定義 ViewGroup 的難點在於,子控件位置的肯定和佈局大小的肯定。不像 單個 View 子要花粉好模式,測量好寬度就搞定了,ViewGroup 的長寬根據子 View 的數量和單個的大小變化而變化。這就是最大的坎,因此該如何肯定 ViewGroup 的大小呢?java
這裏 我爲你們設計一個 相似 LinearLayout 線性佈局的 ViewGroup 做爲範例。android
首先,若是是一個 LinearLayout 那麼當設置 wrap_content 時,他就會以子空間中最寬的那個爲它的寬度。同時在高度方面會是全部子控件高度的總和。因此咱們先寫兩個方法,分別用於測量 ViewGroup 的寬度和高度。編程
private int getMaxWidth(){ int count = getChildCount(); int maxWidth = 0; for (int i = 0 ; i < count ; i ++){ int currentWidth = getChildAt(i).getMeasuredWidth(); if (maxWidth < currentWidth){ maxWidth = currentWidth; } } return maxWidth; } private int getTotalHeight(){ int count = getChildCount(); int totalHeight = 0; for (int i = 0 ; i < count ; i++){ totalHeight += getChildAt(i).getMeasuredHeight(); } return totalHeight; }
對於 ViewGroup 而言咱們能夠粗略的分爲兩種模式:固定長寬模式(match_parent),自適應模式(wrap_content),根據這兩種模式,就能夠對 ViewGroup 的繪製進行劃分。這裏關於 measureChildren 這個方法,他是用於將全部的子 View 進行測量,這會觸發每一個子 View 的 onMeasure 函數,可是你們要注意要與 measureChild 區分,measureChild 是對單個 view 進行測量ide
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); measureChildren(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int heightMode= MeasureSpec.getMode(heightMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){ int groupWidth = getMaxWidth(); int groupHeight= getTotalHeight(); setMeasuredDimension(groupWidth, groupHeight); }else if (widthMode == MeasureSpec.AT_MOST){ setMeasuredDimension(getMaxWidth(), height); }else if (heightMode == MeasureSpec.AT_MOST){ setMeasuredDimension(width, getTotalHeight()); } }
整完上面這些東西,咱們的佈局大小七十九已經出來了,然咱們在活動的佈局文件裏面加上它,並添加上幾個子 View 而後運行一下,先看看效果:函數
<com.entry.android_view_user_defined_first.views.MyLinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/colorAccent"> <Button android:layout_width="100dp" android:layout_height="50dp" android:text="qwe"/> <Button android:layout_width="250dp" android:layout_height="150dp" android:text="qwe"/> <Button android:layout_width="200dp" android:layout_height="75dp" android:text="qwe"/> </com.entry.android_view_user_defined_first.views.MyLinearLayout>
咱們看見佈局出來了,大小好像也沒啥問題,可是子 View 呢??! 這麼沒看見子 View 在看看代碼,系統以前然咱們重寫的 onLayout() 仍是空着的呀!!也就是說,子 View 的大小和位置根本就尚未進行過設定!讓咱們來重寫下 onLayout() 方法。佈局
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int count = getChildCount(); int currentHeight = 0; for (int i = 0 ; i < count ; i++){ View view = getChildAt(i); int height = view.getMeasuredHeight(); int width = view.getMeasuredWidth(); view.layout(l, currentHeight, l + width, currentHeight + height); currentHeight += height; } }
成功了有木有!學習
因爲本文是本身學習過程的總結,若是文中有錯誤,但願你們能在評論區指出動畫
最後,祝你們編程愉快!設計