摘要:層面中可以通過方法攔截事件傳遞,返回代表同一事件列不再向下傳遞給子,返回代表事件繼續傳遞,默認返回。同時注冊兩者事件傳遞順序,方法將會先于方法執行,并且方法可能執行多次事件。如此反復執行初始化布局繪制過程容易造成性能問題。
View 和 ViewGroup
View 是 Android 中最基本的 UI 組件,在屏幕上繪制一塊矩形區域。
ViewGroup 是一種特殊的 View,它可以包含多個子 View 和子 ViewGroup,用于放置、組織、管理視圖結構。
常用控件和布局的繼承結構:
LinearLayout 和 RelativeLayout 性能對比Android Project 默認生成的 avtivity_main.xml 布局文件中,根結點使用 RelativeLayout,然而作為頂級 View 的 DecorView 則是垂直方向的 LinearLayout,從上至下分為標題欄、內容欄。常用的 setContentView() 方法就是為內容欄設置布局。
RelativeLayout 的子 View 需要兩次 onMeasure() 過程,而 LinearLayout 只需一次,但是當 LinearLayout 設置 weight 屬性后,同樣需要兩次 onMeasure() 過程。
在不影響層級深度的情況下,推薦使用 Linearlayout 而非 RelativeLayout。
DecorView 層級深度已知且固定,標題欄與內容欄,采用 RelativeLayout 并不會降低層級深度,因此使用 LinearLayout 效率更高。
Project 默認使用 RelativeLayout 作為根結點,是希望開發者能夠盡量減少 View 層級結構,避免使用 LinearLayout 多層嵌套完成布局。
LayoutInflaterLayoutInflater inflate() 方法用于動態加載布局,將 XML 布局文件實例化為其對應的 View 對象。
public View inflate(int resource, ViewGroup root) // 方法一 public View inflate(int resource, ViewGroup root, boolean attachToRoot) // 方法二inflate() 方法參數詳解
resource(int): 需要加載的 XML 布局資源的 ID
root(ViewGroup): 設置加載的布局的父級層次結構
attachToRoot(boolean): 是否將加載的布局附加到父級層次結構
情況一: root 為 null;
如果 root 為 null,attachToRoot 參數將失去意義。
無需將 resource 指定的布局添加到 root 中,同時沒有任何 ViewGroup 容器來協助 resource 指定的布局的根元素生成布局參數 LayoutParams。
情況二: root 不為 null,attachToRoot 為 true;
將 resource 指定的布局添加到 root 中,inflate() 方法返回結合后的 View,其根元素是 root。View 將會根據它的父 ViewGroup 容器的 LayoutParams 進行測量和放置。
使用方法一即未設置 attachToRoot 參數時,如果 root 不為 null,attachToRoot 參數默認為true。
情況三: root 不為 null,attachToRoot 為 false;
無需將 resource 指定的布局添加到 root 中,inflate() 方法返回 resource 指定的布局 View,根元素是自身的最外層,View 不存在父 ViewGroup,但是可以根據 root 的 LayoutParams 進行測量和放置。
情況三不解之處在于,既然 attachToRoot 為 false,無需將 resource 指定的布局添加到 root 中,那么為什么 root 仍然不為 null?創建的 View 必然包含 layout 屬性,但是這些屬性需要在 ViewGroup 容器中才能生效,根據 ViewGroup 容器的 LayoutParams 進行測量和放置 View。
情況三的意思是,無需將 View 添加到某個 ViewGroup 容器中,卻又能根據這個 ViewGroup 容器的 LayoutParams 進行測量和放置 View。
情況一和情況三依賴手動添加 View。
多個參數版本的 inflate() 方法最終匯合調用:
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)解析 XML 格式數據
Pull 解析方式基于事件驅動方式,Android 中使用 XmlPullParser 對象,調用 setInput() 方法傳遞數據給解析器。開始循環解析,通過 getEventType()方法獲取當前解析事件,如果當前解析事件并非 END_DOCUMENT,調用 next() 方法獲取下一個解析事件。針對不同事件處理,getName() 方法可以獲得當前節點名字(tag name),nextText() 方法可以獲得當前節點內的具體內容(TEXT)。
Events(事件):
START_DOCUMENT 開始文檔
START_TAG 開始標簽
TEXT 文本內容
END_TAG 結束標簽
END_DOCUMENT 結束文檔
XML(可擴展標記語言)組成部分:
Declaration(聲明):XML 文件首行聲明一些文檔信息 。
Tag(標簽):以 < 開頭,以 > 結尾。包括:start-tag()、end-tag()、empty-element tag(
Text(文本):開始與結束 tag 之間的文本內容。
Attribute(屬性):位于開始 tag 之中,以鍵值對形式補充說明 tag 。
視圖繪制流程onMeasure() 決定 View 的大小
onLayout() 決定 View 在 ViewGroup 中的位置
onDraw() 繪制 View
onMeasure()
視圖大小的測量過程,是由父視圖、布局文件、以及視圖本身共同完成的。
父視圖提供參考大小(MeasureSpec: specSize, specMode)給子視圖
UNSPECIFIED 子視圖按照自身條件設置成任意的大小
EXACTLY 父視圖希望子視圖的大小應該由 specSize 來決定
AT MOST 子視圖最大只能是 specSize 中指定的大小
布局文件中指定視圖的大小
MATCH_PARENT
WRAP_CONTENT
視圖本身最終決定大小
onLayout()
根據測量出來的(onMeasure())寬度和高度確定視圖的位置。關鍵方法:public void layout (int l, int t, int r, int b) 方法接收左、上、右、下的坐標。
onDraw()
完成測量(onMeasure())和布局操作(onLayout())之后,創建 Canvas 對象繪制視圖。
事件分發機制重要方法:
dispatchTouchEvent()
onInterceptTouchEvent()
onTouchEvent()
事件分發順序:由 Activity 開始先傳遞給 ViewGroup 再傳遞給 View。
Activity 層面事件分發始于 Activity.dispatchTouchEvent() 方法,傳遞事件至 Window 的根視圖。
若最終沒有視圖消費事件則調用 Activity.onTouchEvent(event) 方法。
ViewGroup 層面ViewGroup 中可以通過 ViewGroup.onInterceptTouchEvent() 方法攔截事件傳遞,返回 true 代表同一事件列不再向下傳遞給子 View,返回 false 代表事件繼續傳遞,默認返回 false。
事件遞歸傳遞至子 View 的 View.dispatchTouchEvent() 方法,如果事件被子 View 消費,則返回 true,ViewGroup 將無法再處理事件。
如果沒有子 View 消費事件則判斷 ViewGroup 中是否存在已注冊的事件監聽器(mOnTouchListener),存在則調用它的 ViewGroup.OnTouchListener.onTouch() 方法,如果 onTouch() 方法返回 false 即未消費事件,則進一步去執行 ViewGroup.onTouchEvent(event) 方法。
View 層面View.dispatchTouchEvent() 方法:首先判斷 View 中是否存在已注冊的事件監聽器(mOnTouchListener),存在則調用它的 View.OnTouchListener.onTouch() 方法,如若 onTouch() 方法返回 false 即未消費事件,則進一步去執行 View.onTouchEvent(event) 方法。
View 可以注冊事件監聽器(Listener)實現 onClick(View v)、onTouch(View v, MotionEvent event) 方法。相比 onClick() 方法,onTouch() 方法能夠做的事情更多,判斷手指按下、抬起、移動等事件。同時注冊兩者事件傳遞順序,onTouch() 方法將會先于 onClick() 方法執行,并且 onTouch() 方法可能執行多次(MotionEvent 事件:ACTION_DOWN、ACTION_UP、ACTION_MOVE)。如若設置 onTouch() 方法返回值為 true,事件視為被 onTouch() 方法消費,不再繼續向下傳遞給 onClick() 方法。
布局性能優化優化布局層級
每個控件和布局都需要經過初始化、布局、繪制過程才能呈現出來。當使用多層嵌套的 LinearLayout 以致產生較深的視圖層級結構,更甚者在 LinearLayout 中使用 layout_weight 參數,導致子 View 需要兩次 onMeasure() 過程。如此反復執行初始化、布局、繪制過程容易造成性能問題。
需要開發者檢查布局、修正布局,可以借助 Lint 工具發現布局文件中的視圖層級結構里值得優化的地方,同時扁平化處理原本多層嵌套的布局,例如使用 RelativeLayout 作為根節點。
使用
通過使用
layout1.xml:
layout2.xml:
最終布局視圖層級結構:
layout2.xml:
最終布局視圖層級結構:
懶加載 View
有時布局中包含很少使用的復雜視圖,可以在需要時加載視圖,減少內存使用,加快渲染速度。ViewStub 是一個輕量級視圖,在構建視圖層級結構中消耗資源較小。但是實際項目使用中,開發者習慣切換視圖的 Visibility 而不是使用 ViewStub。
屏幕大小適配手段使用 wrap_content 和 match_parent,布局盡可能自適應屏幕大小。
wrap_content 讓當前控件的大小能夠剛好包含住里面的內容。
match_parent 讓當前控件的大小和父布局的大小一樣。
使用配置限定符,程序在運行時根據當前設備的配置自動加載合適的資源。
Android 常見的限定符:
屏幕特征 | 限定符 |
---|---|
大小 | small, normal, large, xlarge |
分辨率 | ldpi, mdpi, hdpi, xhdpi, xxhdpi |
方向 | land, port |
使用 Nine-Patch 圖片 ,從圖片資源角度,支持不同屏幕大小,Nine-Patch 圖片允許指定哪些區域可以拉伸而哪些區域不可以。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/110408.html
摘要:層面中可以通過方法攔截事件傳遞,返回代表同一事件列不再向下傳遞給子,返回代表事件繼續傳遞,默認返回。同時注冊兩者事件傳遞順序,方法將會先于方法執行,并且方法可能執行多次事件。如此反復執行初始化布局繪制過程容易造成性能問題。 View 和 ViewGroup View 是 Android 中最基本的 UI 組件,在屏幕上繪制一塊矩形區域。 ViewGroup 是一種特殊的 View,它...
摘要:方法根據子項所處的位置判斷具體類型并返回。調用方法解除子項與之間的關聯。自定義適配器適配器繼承自,并將泛型指定為內部類。使用支持多種布局方式借助能夠靈活地將列表控件放入不同的容器。 ListView 和 RecyclerView 最常用和最難用的控件 由于手機屏幕空間有限,無法顯示全部內容。當有大量數據需要展示的時候,借助列表控件。通過手指上下滑動,使得屏幕內外的數據不斷進出。 最基本...
閱讀 2793·2021-10-11 10:57
閱讀 2401·2021-08-27 16:20
閱讀 1384·2019-08-30 13:03
閱讀 1563·2019-08-30 12:50
閱讀 3336·2019-08-29 14:16
閱讀 1561·2019-08-29 11:12
閱讀 1613·2019-08-28 17:53
閱讀 2893·2019-08-27 10:58