Android進階教程之ViewGroup自定義布局

 更新時間:2019年06月23日 09:15:02   作者:水中魚之1999   我要評論
這篇文章主要給大家介紹了關于Android進階教程之ViewGroup自定義布局的相關資料,文中通過示例代碼介紹的非常詳細,對各位Android開發者們具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

前言

在我們的實際應用中, 經常需要用到自定義控件,比如自定義圓形頭像,自定義計步器等等。但有時我們不僅需要自定義控件,舉個例子,FloatingActionButton 大家都很常用,所以大家也很經常會有一種需求,點擊某個 FloatingActionButton 彈出更多 FloatingActionButton ,這個需求的一般思路是寫 n 個 button 然后再一個個的去設置動畫效果。但這實在是太麻煩了,所以網上有個 FloatingActionButtonMenu 這個開源庫,這就是利用到了自定義布局 「ViewGroup」,現在就讓我給他家介紹下,如何自定義布局 「layout」。

難點

相比于自定義 View ,自定義 ViewGroup 的難點在于,子控件位置的確定和布局大小的確定。不像 單個 View 子要花粉好模式,測量好寬度就搞定了,ViewGroup 的長寬根據子 View 的數量和單個的大小變化而變化。這就是最大的坎,所以該如何確定 ViewGroup 的大小呢?

步驟

這里 我為大家設計一個 類似 LinearLayout 線性布局的 ViewGroup 作為范例。

首先,如果是一個 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 進行測量

 @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());
  }
 }

重寫 onLayout

整完上面這些東西,我們的布局大小七十九已經出來了,然我們在活動的布局文件里面加上它,并添加上幾個子 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;
  }
 }

再運行一下看看:


成功了有木有!

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。

相關文章

  • 玩轉Kotlin 徹底弄懂Lambda和高階函數

    玩轉Kotlin 徹底弄懂Lambda和高階函數

    這篇文章主要幫助大家徹底弄懂Lambda和高階函數,玩轉Kotlin,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Android中init.rc文件的解析 分享

    Android中init.rc文件的解析 分享

    本文分析Android中如何解析init.rc文件,重點描述了on action內的解析,并從解析的過程中總結出init.rc的語法規范。
    2013-06-06
  • Android實現帶列表的地圖POI周邊搜索功能

    Android實現帶列表的地圖POI周邊搜索功能

    這篇文章主要為大家詳細介紹了Android實現帶列表的地圖POI周邊搜索功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android中監聽未接來電的2種方法

    Android中監聽未接來電的2種方法

    這篇文章主要介紹了Android中監聽未接來電的2種方法,本文講解了使用廣播接收器 BrocastReceiver和使用 PhoneStateListener二種方法,需要的朋友可以參考下
    2015-04-04
  • Kotlin自定義實現支付密碼數字鍵盤的方法實例

    Kotlin自定義實現支付密碼數字鍵盤的方法實例

    這篇文章主要給大家介紹了關于Kotlin如何自定義實現支付密碼數字鍵盤的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-07-07
  • Android App開發中使用RecyclerView替代ListView的實踐

    Android App開發中使用RecyclerView替代ListView的實踐

    RecyclerView是Android L即5.0版本以來新加入的一個組件,主要用來實現item的瀑布式排列,因而被人們廣泛認為用來替代ListView,這里我們就來看一下Android App開發中使用RecyclerView替代ListView的實踐:
    2016-06-06
  • Android基于Glide v4.x的圖片加載進度監聽

    Android基于Glide v4.x的圖片加載進度監聽

    本篇文章主要介紹了基于Glide v4.x的圖片加載進度監聽的示例代碼,具有一定的參考價值,有興趣的可以了解一下
    2017-08-08
  • Android 5.0以上Toast不顯示的解決方法

    Android 5.0以上Toast不顯示的解決方法

    最近在開發中我們經常會在適配5.0以后的機型遇到各種各樣的問題,其中有一個不大不小的問題就是:Toast不顯示問題,這篇文章就給大家總結了Android 5.0以上Toast不顯示的原因與解決方法,有需要的朋友們可以參考借鑒,下面來一起看看吧。
    2016-11-11
  • Android中簡單的電話管理與短信管理App編寫實例

    Android中簡單的電話管理與短信管理App編寫實例

    這篇文章主要介紹了Android中簡單的電話管理與短信管理App編寫實例,包括監聽電話的呼叫狀態以及短信群發聯系人選擇等基本功能的實現,代碼突出要點,需要的朋友可以參考下
    2016-04-04
  • Android實現搖一搖功能

    Android實現搖一搖功能

    這篇文章主要為大家詳細介紹了Android實現搖一搖功能的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11

最新評論

湖北11选5走势图爱彩乐 天津麻将胡法图解法 广东11选5直播 中原风采22选开奖今天 金十数据 葡萄牙足球队 贵州11选五走势图遗漏 捕鸟的游戏有哪些 韩国快乐8开奖结果查询 招财猫娱乐棋牌官网 好运快3赚佣金 快3娱乐平台 北京pk10冠军软件 成都双层井盖深圳风采厂家 闲来麻将下载手机版 上证指数是什么意思 北京快中彩质合走势