1. 程式人生 > >自定義View關於measure流程的基本思路整理

自定義View關於measure流程的基本思路整理

在《MeasureSpec的簡單說明》這篇文章中對android中View的MeasureSpec測量方法做了詳細的說明,今天這篇博文就Measure的測量做一個簡單的總結。本文著重點在於怎麼將android的一般測量規律應用到自己的自定義View中去,同時也算是給指定一個確定的思路。而對這些測量的內部細節不多做說明。

其實對於Measure要分兩個具體的情況:

1)如果測量的是一個View,那麼通過View這個類帶的measure(int widthMeasureSpec, int heightMeasureSpec)方法就可以完成測量過程。

2)如果是ViewGroup的話,需要先完成childView的測量,這是一個遞迴的過程。根據childView寬和高在做一些其他的處理,比如ListView或者GridView的onMeasure方法。

正如上面所說,view的Measure方法,是呼叫measureint widthMeasureSpec,int heightMeasureSpec),注意裡面的引數,是根據widthSpec/heightSpec來最終確定view的大小的。所說在我們自定義view如果需要測量的話需要先分別獲取view的widthSpec和heightSpec(注:為了描述方便下文widthSpec和heightSpec統統用Spec來表示)。如《MeasureSpec的簡單說明》所說,獲取Spec的方法有兩個

a)呼叫ViewGroup類的getChildMeasureSpec(int spec, int padding, int childDimension) 來獲取View的Spec

.通常來說第一個引數傳遞的是View的parentView的spec。ViewGroupmeasureChild方法可以說是這個方法怎麼使用的參考書,這個方法是ViewGroup用來對childView進行測量的時候呼叫:

    protected void measureChild(View child, int parentWidthMeasureSpec,  
                int parentHeightMeasureSpec) {  
            final LayoutParams lp = child.getLayoutParams();  
      
            final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,  
                    mPaddingLeft + mPaddingRight, lp.width);  
            final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,  
                    mPaddingTop + mPaddingBottom, lp.height);  
            //執行child的measure流程  
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);  
     }            

   先獲取ViewGroup的Spec即parentSpec,再加上childView的LayoutParams這兩個資訊,然後呼叫getChilMeasureSpec獲取childView的Spec,既然獲取到了Spec了,那麼在呼叫View類的.measure方法把這個Spec交給measure方法處理就是了。

使用案例:ListView對ItemView進行測量的時候獲取ItemView的widthSpec就這麼個思路,具體在measureScrapChild這個方法裡面,相關程式碼如下:

//獲取itemView的LayoutParams
	   LayoutParams p = (LayoutParams) child.getLayoutParams();     
		//非空判斷
		if (p == null) {
            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
            child.setLayoutParams(p);
        }
        //省略兩行程式碼
		//根據父spec+chid的layoutParams
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
                mListPadding.left + mListPadding.right, p.width);

b)通過makeMeasureSpec(int size, int mode)方法來獲取View的Spec值

該方法為ViewGroup類的一個靜態方法,事實上getChildMeasureSpec這個方法最後也就是呼叫了makeMeasureSpec!

使用案例:ListView進行測量的時候獲取ItemView的heightSpec就是這麼個思路,具體在measureScrapChild這個方法裡面,相關程式碼如下:

 int lpHeight = p.height;
        int childHeightSpec;
        if (lpHeight > 0) {
		    //根據高度和設定的measureSpec來獲取高度spec
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
通過a或者b說的兩個方法獲取到View的Spec值之後就可以呼叫view的measure方法進行view的測量了,具體是使用a還是b,這個倒是根據具體需求具體分析了,沒有固定的要求,可根據需求靈活處理之。ListView關於ItemView的測量完整程式碼如下:
	private void measureScrapChild(View child, int position, int widthMeasureSpec) {
       //獲取itemView的LayoutParams
	   LayoutParams p = (LayoutParams) child.getLayoutParams();     
		//非空判斷
		if (p == null) {
            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
            child.setLayoutParams(p);
        }
        //省略兩行程式碼
		//根據父spec+chid的layoutParams
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
                mListPadding.left + mListPadding.right, p.width);
      
   	  int lpHeight = p.height;
        int childHeightSpec;
        if (lpHeight > 0) {
		    //根據高度和設定的measureSpec來獲取高度spec
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
		//測量child的寬和個搞
        child.measure(childWidthSpec, childHeightSpec);
	
    }

所以上面的對View的測量總的來說其實是很簡單的:第一你只需要先獲取View的Spec值,而且不需要只要具體的Spec得到的內部細節;第二,呼叫View的measure值把

得到的Spec傳給measure方法即可。當然如果需要的話完全可以呼叫setMeasureDimension(int width,int height)來確定一個View的寬和高。具體測量的規則,不同的ViewGroup因為佈局不同有著不同的測量邏輯,但是總的思路上是不會變化的,但是測量基本上會少不了Spec的計算就是了!

最後關於這個measure的靈活應用的使用案例可參考這篇部落格,該篇部落格主要就是運用了measureChildren方法對所有的ChildView進行測量,measureChildren方法其實也就是迴圈呼叫了measureChild方法而已。

相關推薦

定義View關於measure流程基本思路整理

在《MeasureSpec的簡單說明》這篇文章中對android中View的MeasureSpec測量方法做了詳細的說明,今天這篇博文就Measure的測量做一個簡單的總結。本文著重點在於怎麼將android的一般測量規律應用到自己的自定義View中去,同時也算是給指定一個確

Pytohn定義函數基本操作

htm 函數功能 都沒有 proc stat 運算 watermark 傳遞參數 普通 本章包含知識點1、定義函數;2、變量和全局變量區別;3、形參,實參,默認參數;4、多參傳遞,榮譽處理;運行環境 ipython ,交互功能比python清晰,明了。函數介紹函數是編程語言

MySQL定義函式用法詳解-複合結構定義變數/流程控制

自定義函式 (user-defined function UDF)就是用一個象ABS() 或 CONCAT()這樣的固有(內建)函式一樣作用的新函式去擴充套件MySQL。 所以UDF是對MySQL功能的一個擴充套件 建立和刪除自定義函式語法: 建立UDF:   CREATE 

精通Spring Boot——第十八篇:定義認證流程

前兩篇簡單介紹了一下使用Spring Security 使用Http Basic登入,以及Spring Security如何自定義登入邏輯。這篇文章主要介紹如何使用handler來定義認證相關的流程。 先做一些自定義的操作,如配置自定義登入頁,配置登入請求URL等。 當我們使用Spring Security時

定義view流程(結合原始碼分析)

一、View的繪製流程 主要是:測量(measure)、佈局(layout)、繪製(draw)三大流程。 對於一個普通View(不是容器) 主要是關心測量和繪製兩個過程,測量可以確定自身的寬、高、大小,繪製可以顯示出view的具體內容(呈現在螢幕上的)。 對於

Android繪圖系列(二)——定義View繪製基本圖形

這個系列主要是介紹下Android自定義View和Android繪圖機制,自己能力有限,如果在介紹過程中有什麼錯誤,歡迎指正 前言 在上一篇Android繪圖系列(一)——自定義View基礎中我們瞭解自定義View相關的基本知識,不過,這些東西依舊還

定義View 篇一--------《定義View流程分析》

本文部分內容參考自掘金網:點選開啟連結座標圖解:概述Android已經為我們提供了大量的View供我們使用,但是可能有時候這些元件不能滿足我們的需求,這時候就需要自定義控制元件了。自定義控制元件對於初學者總是感覺是一種複雜的技術。因為裡面涉及到的知識點會比較多。但是任何複雜的

如何自己實現一個可定義業務流程步驟的工作流

專案功能需求簡述 由於業務需要,需要一個申請-審批的工作流,並且業務流程是不固定的,需要能靈活配置,比如現在是:開始->部門經理審批->結束,可能之後就會變為開始->部門經理審批->部門領導審批->結束。因此不能把程式碼寫死,必須

R語言定義函式及基本分支迴圈結構

使用者自定義函式: 使用者自定義函式名<- function(引數列表){ 計算步驟n Return(函式值) } 分支結構: If(關係表示式){語句} If(關係表示式){語句}else{語句} Ifelse(關係表示式,語句1,語句2) switch(R物件,值

ANDROID定義檢視——onLayout原始碼 流程 思路詳解

簡介: 在自定義view的時候,其實很簡單,只需要知道3步驟:    1.測量——onMeasure():決定View的大小    2.佈局——onLayout():決定View在ViewGroup中的位置    3.繪製—

PHP整理筆記六定義函數

php 自定義函數一.標準函數 標準的PHP發行包中有1000多個標準函數,這些標準函數都是系統內置的,不需要用戶自己創建而可以直接使用。<? echo md5(‘123456‘); //MD5函數對字符串進行加密處理?> 二.自定義函數 PHP內置函數允許和文件進

Notification的基本用法以及使用RemoteView實現定義布局

解決 edi ngs 取消 ets lsp 過程 net tde Notification的作用 Notification是一種全局效果的通知,在系統的通知欄中顯示。既然作為通知,其基本作用有: 顯示接收到短消息、即時信息等 顯示客戶端的推送(廣告、優惠、新聞等)

定義TempData跨平臺思路

using add 初始化 obj logs temp 模式 既然 [] 一:TempData的自定義實現。。。 TempData是用Session實現的,既然是Session,那模式是線程方式。。。這樣的Session是沒法進行跨平臺的。。。 那麽這就涉及到如何在多臺機器

定義流程gooflow2.0+定義表單

log ges bapi cnblogs 語句 參與者 源碼 -1 通過 一、功能簡介 gooflow功能清單1、自定義流程繪制2、自定義屬性添加3、支持3種步驟類型普通審批步驟自動決策步驟手動決策步驟 4、決策方式(支持js決策,sql語句決策) 5、審批人員參與方

VS下WPF定義控件的基本步驟和基本代碼實現

emp don 謝謝 generic 管理器 參數 bubuko 類的屬性 typeof 一、自定義控件的基本步驟: (本示例項目名稱為:W;添加的自定義控件名稱為) 1、 在“解決方案資源管理器”窗口的項目名上: 右擊à添加à新建項(Ctrl+Shift+A)

定義View分類與流程

ces ted function ram 註意 measure fin 利用 href 自定義View分類與流程(進階篇)## 轉載出處: http://www.gcssloop.com/customview/CustomViewProcess/ 自定義View繪制流程

div層次整理 / 定義pycharm補全 / 註釋 /keymap /tab

div css pycharm keymap div css 結構,div套div層次過多。漏個div多個div什麽的,加上結束標記就好排查多了。 在django template裏自定義補全 div層次整理 / 自定義pycharm補全 / 註釋 /keymap /tab

SpringCloud系列五:Ribbon 負載均衡(Ribbon 基本使用、Ribbon 負載均衡、定義 Ribbon 配置、禁用 Eureka 實現 Ribbon 調用)

control context .mm 別名 void 用戶 size ali ram 1、概念:Ribbon 負載均衡 2、具體內容 現在所有的服務已經通過了 Eureka 進行了註冊,那麽使用 Eureka 註冊的目的是希望所有的服務都統一歸屬到 Eureka 之中進

C# 繪制PDF圖形——基本圖形、定義圖形、色彩透明度

mat alternate ffi 方法 ref lin 設置 ice pre 引言 在PDF中我們可以通過C#程序代碼來添加非常豐富的元素來呈現我們想要表達的內容,如繪制表格、文字,添加圖形、圖像等等。在本篇文章中,我將介紹如何在PDF中繪制圖形,並設置圖形屬性的操作。

mysql的學習(七)-定義函數和流程控制

returns spa 會員 返回 類型 mysq -- create decimal DELIMITER // (設置結束符 其實我也不太明白為啥要這樣 記住就行把) CREATE FUNCTION ym_date(mydate DATE) (創建函數