前言
Android開發(fā)中要注重的細節(jié)很多,本文則是來總結一下開發(fā)過程中非常實用的小技巧。我都是站在巨人的肩膀上才能了解這些技巧的存在,寫作本文的靈感來源于Frank Lee的博文:Android 開發(fā)中的那些正確姿態(tài) 。 文章中有些知識講的并不是很仔細,我則按照他的思路在學習實踐并總結一下,目錄如下:
- Android 布局優(yōu)化之< include >、< merge >、ViewStub
- 使用LinearLayout自帶的分割線divider屬性來代替1dp View方案
- 使用 android.support.v4.widget.Space輕量級控件來占據(jù)一定的空間
- 使用shape減少圖片資源占比以及色彩漸變的坑
- LinearLayout 中 android:weightSum 和 android:layout_weight 一起使用更配哦。
- 使用 android:descendantFocusability 解決 ViewGroup 與 Children View 之間的焦點占用問題。
- 使用 android:fillViewport=”true” 可以將 ScrollView 填滿屏幕
- Elevation 實現(xiàn)控件陰影效果
Android 布局優(yōu)化之< include >、< merge >、ViewStub
- < include > 布局重用
- < merge > 減少視圖層級
- ViewStub 延時加載
< include >估計不用多說,它允許在一個布局中引入另外一個布局,從而提高布局復用。< merge >標簽在優(yōu)化UI結構上起著很重要的作用,通過刪減多余或者額外的視圖層級從而達到優(yōu)化整個Android Layout的結構。例如,我們用< include > 來引入一個布局,這個被引入的布局最外層是LinearLayout,而事實上,我們可能并不需要這個LinearLayout布局嵌套,這時候我們可以用< merge >標簽來替換LinearLayout,這樣做即是把布局內容直接引入,減少了視圖層級。
著重講解一下ViewStub,它是一個不可見、無尺寸、在需要被加載的時候才加載的一個控件。這里我們可以類比一下View的可見性就明白了。假設我們在首次加載的時候不需要加載某個控件,這時我們可以把這個控件設置為不可見(View.GONE)。但是事實上,這個控件在Activity.onCreate()時,還是被實例化被加載了,只是不可見而已,這就導致了資源的不必要加載。而ViewStub剛好可以擬補這個缺陷,它會在需要加載的時候才被加載。
因此,不是必須顯示的布局使用 ViewStub 代替后減少界面首次加載時資源消耗,提升最初加載速度
基本用法如下:
<ViewStub
android:id="@+id/viewStub"
android:layout="@layout/avtivity_cardviewdemo" //指定被加載替換的布局
android:inflatedId="@id/btn_stub2" //指定被加載替換布局的ID
android:layout_width="match_parent"
android:layout_height="wrap_content" />
需要加載時:
try {
mView = mViewStub.inflate(); //返回一個View實例
} catch (Exception e) {
e.printStackTrace();
mView.setVisibility(View.VISIBLE);
}
為什么要捕獲異常呢?這是因為ViewStub的inflate()方法只能被調用一次 ,調用之后就移出了父布局,再次調用就會拋出:
ViewStub must have a non-null ViewGroup viewParent
這種寫法主要是能獲取到返回的View實例,從而避免了findViewById操作。當然,其實可以避免捕獲異常,直接寫:
mViewStub.setVisibility(View.VISIBLE);
我們還可以添加ViewStub加載監(jiān)聽事件,即 mViewStub.setOnInflateListener。
參考自:
Android布局優(yōu)化之ViewStub、include、merge
使用LinearLayout自帶的分割線divider屬性來代替1dp View方案
divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#dddddd" />
<size android:height="1dp" />
</shape>
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:divider="@drawable/divider"
android:showDividers="middle"
android:layout_width="match_parent"
android:layout_height="match_parent">
......
</LinearLayout>
android:showDividers 屬性可設置以下值:
- none 不顯示分隔線
- beginning 在LinearLayout的開始處顯示分隔線
- end 在LinearLayout的結尾處顯示分隔線
- middle 在LinearLayout中每兩個組件之間顯示分隔線
使用 android.support.v4.widget.Space輕量級控件來占據(jù)一定的空間
網(wǎng)上查了一下,說是可用于在通用布局中的組件之間創(chuàng)建間隙,其draw()為空,組件之間的距離使用Space會提高繪制效率,特別是對于動態(tài)設置間距會更方便高效,正因為draw()為空,所以我們不能對Space設置背景色。
感覺這個控件還是有點雞肋呀,如果是單純的設置組件之間的間隙,直接設置 layout_marginTop值就可以了,如果想要動態(tài)設置間距,放一個空View,背景色為布局背景就可以了,可能的確會影響繪制效率,想了解Space可以看:學Android Space控件,只看這篇文章就行了
使用shape減少圖片資源占比以及色彩漸變的坑
顏色漸變< gradient >標簽之坑爹的 @android:color/transparent
ViewGroup 與 Children View 之間的焦點占用問題
android:descendantFocusability 屬性值有以下三種:
- beforeDescendants ViewGroup會優(yōu)先其子類控件獲取焦點
- afterescendants ViewGroup只有當其子類控件不需要獲取焦點時才獲取焦點
- blocksescendants ViewGroup會覆蓋子類控件而直接獲取焦點
例子見:android:descendantFocusability屬性在ListView中的妙用
Elevation 實現(xiàn)控件陰影效果
- api >= 21 時,通過 android:elevation 或者 setElevation() 實現(xiàn)
- api < 21 時,通過 ViewCompat.setElevation(View view, float elevation) 實現(xiàn),前提要設置 view 的背景。
但需要注意的是,該控件必須要有背景顏色,沒有背景顏色是沒有陰影效果的。而有的控件比如Button有默認主題的,主題里已經有了elevation,所以在設置elevation就沒有效果,這時可以設置android:stateListAnimator="@null"把默認動畫置空,然后在設置背景顏色和elevation。
參考: