#本文涉及到的知識點
- 簡單的說明以下佈局優化的重要性
- 一些佈局使用的注意事項
- include、merge與ViewStub的使用
- ConstraintLayout的使用
##1.佈局優化的重要性
在日常開發中對於佈局我們很少注重效能,主要注重的就是相應的展示問題。可能由於介面的複雜程度,使得介面巢狀的層級過多,這樣也就導致了繪製頁面的卡頓現象。增加了GPU渲染的複雜程度。這裡引用一張圖片來說明相應的問題。
怎麼檢視呢?手機設定->開發者選項->除錯GPU過度渲染 開啟之後你就能看到你的APP到底有沒有過度繪製了。如果你看見的是一片紅,那麼恭喜你...你必須考慮相應的優化了!說了這麼多,其實最重要的就是減少層級、減少相應的過度繪製,就能有效的對佈局進行相應的優化。所以在Android做一些簡單的佈局優化還是有必要的。。。
##2.一些佈局使用的注意事項
這裡先提出個問題,大家想一下?如果專案中有這樣一個需求,豎直排列兩行每行兩個元素,大家怎麼去實現呢?相信有的人會使用相對佈局,有的人會使用線性佈局,那麼問題就來了,如果你使用線性佈局的話,就會存在佈局巢狀的問題,就平白的多了一層佈局巢狀,平時開發的時候這樣的問題很多,如果你多加註意的話,你會發現很多這樣的問題。
這裡我主要想說的是,如果在平時開釋出局的時候,如果在佈局不是很複雜的情況下儘量使用相對佈局,少用線性佈局。但是大家要注意一點,如果佈局複雜的話,或者層級較深的情況下,最好還是使用線性佈局。這裡不知道大家注意沒有,在Android Studio2.+版本的時候,所有預設的佈局都是線性佈局,為什麼呢?我就不在繼續深入講解了,感興趣的同學可以看看尹star 的->Android中RelativeLayout和LinearLayout效能分析主要是Measure在測量的時候產生的效能消耗!所以這個問題主要看你佈局是否比較複雜。。。其實在現在的版本中,google推薦我們使用的是ConstraintLayout(這個我會在後面詳細的講解)
##3.include、merge與ViewStub的使用
說到佈局優化問題,很難不提及include、merge與ViewStub的使用,但是這些都有相對的侷限性的,下面我們就來一一講解:
###3.1 include的使用和注意事項
這個東西相信大家都不陌生,它能幫我們解決佈局複用的問題,只要include匯入一個佈局就可以了。像這樣:
<include layout="@layout/XXX"/>
複製程式碼
XXX代表引入的佈局。是不是很簡單,那麼我問大家幾個問題?
- 如果在include標籤中我設定相應的layoutxxx的屬性,會對原來的佈局有什麼影響?
- 如果在include標籤中我設定了id,會對原來的佈局有什麼影響?
這些問題,相信細心的人應該會有體會的,但是對於有些人來說,或許很陌生。所以這裡有必要說明一下:
- 當你在include中設定layoutxxx屬性的時候,會覆蓋相應匯入根佈局的layoutxxx屬性,怎麼理解呢?也就是說如果你匯入的佈局是這樣的
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#223344"
android:gravity="center"
android:text="匯入的佈局"
android:textColor="@android:color/white"
android:textSize="20sp" />
</LinearLayout>
複製程式碼
這裡看好,LinearLayout的寬和高是佔用父窗體。如果你要是這麼寫
<include layout="@layout/test_view" />
複製程式碼
的話,會顯示全屏的,就像這個樣子
但是如果你要是寫成這個樣子就不一樣了
<include
layout="@layout/test_view"
android:layout_width="200dp"
android:layout_height="200dp" />
複製程式碼
會變成這個樣子
這裡要特別注意一下。。。
- 當你在include中設定id的時候,會覆蓋相應匯入根佈局的id屬性,也就是說你只能使用include中的id屬性獲取根view了!
###3.2 merge的使用和注意事項
對於新手來說,這個標籤應該很少使用,至少我是這樣的,其實我呆了這麼多公司,也很少有人去用這個,可能我呆的都是小公司吧!哈哈。。。不閒扯了,其實這個標籤主要是針對include匯入的標籤的根佈局來說的,可以減少一個層級的巢狀!
先來說一下這個怎麼看啊!!!不說這個的都是扯淡。。。在Android Studio3.+版本上按照下圖獲取!
中間會彈出一個對話方塊,然後你就點確定,就能檢視相應的檢視樹了。。。
- 當你沒有使用merge標籤的時候,佈局是這個樣子的!
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#223344"
android:gravity="center"
android:text="匯入的佈局"
android:textColor="@android:color/white"
android:textSize="20sp" />
</LinearLayout>
複製程式碼
這個時候你檢視一下檢視樹你會發現會出現下面這個樣子。
我已經用紅框畫出來了,中間有一層LinearLayout作為根佈局,但是如果你把上面的LinearLayout換成merge標籤就不會有中間這層LinearLayout了。這個就不貼圖了,不信的你可以試試。。。
還有一個問題需要注意: 這裡有必要說明一下,如果你要給merge標籤設定一些屬性怎麼辦?其實是這樣的,你可以根據include的父控制元件進行屬性的設定,如果父控制元件是LinearLayout你就可以設定weidge或者相應LinearLayout的特有屬性...這也充分說明了為什麼include可以使用layoutxxx屬性覆蓋根佈局的layoutxxx屬性。
###3.3 ViewStub的使用和注意事項
其實關於這個ViewStub這個標籤,就相當於延時載入,但是有很多侷限性,打個比方說吧!相應在平時開發的時候,都會根據狀態進行一些控制元件的顯示和隱藏吧,一般的處理都是View的setVisibility();但是這裡如果你改變一次之後還能進行改變的話,那麼就不能使用ViewStub這個標籤。因為ViewStub對控制元件只有一次的改變,其實ViewStub在佈局載入的時候已經載入出來了,只是寬和高都是0罷了,當你inflate()的時候,再去載入這個整體的View,達到了延遲載入的目的!
基本的寫法就是這樣,也是匯入一個layout
<ViewStub
android:id="@+id/vs_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/test_view" />
複製程式碼
什麼時候你想載入了,就呼叫View inflate = mVs.inflate();
方法就能讓這個View顯示出來,但是一定要注意,這個方法只能使用一次,切記!切記!切記!重要的事情說三遍,當這個View載入出來的時候,你就可以像對待其他View對待它了,如果你要對這個View做一些特有控制元件的操作,最好強轉一下。。。
基本上上面這三個View優化的標籤我總結的就這麼多,有什麼不對的還請指出,我會立即改正的!!!
##4. ConstraintLayout的使用
關於這個控制元件,其實google早在很早的時候就讓我們去嘗試著使用了,但是在1.0.2那個版本的時候(記不太清楚了)才作為根佈局使用的。
A ConstraintLayout is a ViewGroup which allows you to position and size widgets in a flexible way. Note: ConstraintLayout is available as a support library that you can use on Android systems starting with API level 9 (Gingerbread). As such, we are planning on enriching its API and capabilities over time. This documentation will reflect those changes.
這裡面引用了google的解釋,大概的意思是
ConstraintLayout繼承ViewGroup允許您以靈活的方式定位和調整小部件的大小。 ConstraintLayout可用作支援庫,您可以從API級別9(薑餅)開始在Android系統上使用該支援庫。因此,我們計劃在一段時間內豐富其API和功能。本文件將反映這些更改。
主要是約束內部控制元件位置的佈局,裡面包含關於相對位置的屬性:
- layout_constraintLeft_toLeftOf 當前控制元件的左側和目標控制元件的左側對齊
- layout_constraintLeft_toRightOf 當前控制元件的左側和目標控制元件的右側對齊
- layout_constraintRight_toLeftOf
- layout_constraintRight_toRightOf
- layout_constraintTop_toTopOf
- layout_constraintTop_toBottomOf
- layout_constraintBottom_toTopOf
- layout_constraintBottom_toBottomOf
- layout_constraintStart_toEndOf
- layout_constraintStart_toStartOf
- layout_constraintEnd_toStartOf
- layout_constraintEnd_toEndOf
其實屬性很多,估計讓你記你也記不住,所以總結一下:
這裡所有的都可以這麼去理解,layout_xxxA_toxxxB 理解為,當前控制元件的A側和目標控制元件的B側對齊,你可能還是不理解,拿第一個舉例說明下,就是當前控制元件的左側和目標控制元件的左側對齊,標記了兩個,其他的以此類推。這裡注意裡面設定的引數是目標控制元件的id/父容器只有這兩種可能! 如果你有兩個控制元件,左側的以父控制元件對齊,另一個控制元件以左側的控制元件對齊,這時候如果右側以父控制元件對齊的話,這個控制元件會在右側剩下的空間居中(像下面這樣),但是如果你要是不設定右側的屬性的話,那麼兩個會挨著!(是那個屬性拆散了它們!哈哈)
- layout_constraintHorizontal_bias 水平偏差百分比
- layout_constraintVertical_bias 豎直偏差的百分比
這兩個屬性是針對於上面這個產生偏差的(只能設定以為小數,最大是1),其實我試過,只要你左右或者上下都有約束的時候,這個相應的屬性才生效,否則是無效的(如:一個控制元件左右都有約束,那麼設定layout_constraintHorizontal_bias才會生效,否則是不會生效的,豎直方向的同理)
- android:layout_marginStart
- android:layout_marginEnd
- android:layout_marginLeft
- android:layout_marginTop
- android:layout_marginRight
- android:layout_marginBottom
如果你設定了相應的margin_xxx屬性,那麼主要是產生了相應的邊距,和其他的控制元件都一樣,這裡就不再多做解釋了.
- layout_goneMarginStart
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginTop
- layout_goneMarginRight
- layout_goneMarginBottom
這裡說明一個問題,當你有一個View處於GONE的情況,其他View還以來這個View來進行佈局,那麼就需要設定上面的goneMarginXXX來設定相應的Margin**(PS:這個只有在你依賴的那個約束為GONE的時候才會生效的屬性)**
- android:minWidth 設定佈局的最小寬度
- android:minHeight 設定佈局的最小高度
- android:maxWidth 設定佈局的最大寬度
- android:maxHeight 設定佈局的最大高度
這幾個屬性沒有什麼好說的了!
- layout_constraintDimensionRatio 設定寬高比
這個屬性很有意思:設定相應的寬高比,但是我試了,至少要有三面有約束,否則不起作用,並且寬度和高度都應該設定成"0",引數值可以是"1:1"或者"h,1:1"也可以是"w,1:1"其中h代表限制高度,w代表限制寬度.這裡的比例不管你前面是什麼,後面的比值都是"寬度:高度"
- layout_constraintHorizontal_weight
- layout_constraintVertical_weight
這兩個屬性相當於LinearLayout的weight屬性和LinearLayout的屬性設定是一樣的
- layout_constraintHorizontal_chainStyle
- layout_constraintVertical_chainStyle
- CHAIN_SPREAD 預設樣式(如果某些小部件設定為MATCH_CONSTRAINT,則它們將拆分可用空間)
- CHAIN_SPREAD_INSIDE 但鏈條的終點不會被分散
- CHAIN_PACKED 鏈條的元素將被打包在一起。
這裡我用的時候踩了一個大坑,這裡所謂的鏈式,你必須確保從左至右或者從上至下多有的約束都連著,這裡的連著是都有相應的約束: 如view a 和view b在豎直方向上形成鎖鏈:a的屬性設定為 top_toTopOf = “parent” bottom_toTopOf = “b” b的屬性設定為top_toBottomOf=“a” bottom_toBottom = “parent"切記!切記!切記!都要連上....重要的事情說三遍,否則你是看不見效果的.效果就是上面這張圖的效果!
這裡使用了這個佈局,就能減少佈局的巢狀,也使得繪製的時候能減少GPU的負擔,這樣就能達到佈局優化的目的了!!!
上面這些......基本上就是我在專案中優化佈局時候所做的一些優化,有什麼不妥的地方還請指正!